diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 1ecc7f781fa16c1f0cf67e42c3e6b9db08701c16..0de8de05b38f3aabd28febba61f70e96effa45f0 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -900,6 +900,15 @@ void EncApp::xInitLibCfg()
 #if JVET_AA0061_IBC_MBVD
   m_cEncLib.setIbcMbvd                                           ( m_ibcMbvd );
 #endif
+#if JVET_AC0112_IBC_CIIP
+  m_cEncLib.setIbcCiip                                           ( m_ibcCiip );
+#endif
+#if JVET_AC0112_IBC_GPM
+  m_cEncLib.setIbcGpm                                            ( m_ibcGpm );
+#endif
+#if JVET_AC0112_IBC_LIC
+  m_cEncLib.setIbcLic                                            ( m_ibcLic );
+#endif
 
   m_cEncLib.setUseWrapAround                                     ( m_wrapAround );
   m_cEncLib.setWrapAroundOffset                                  ( m_wrapAroundOffset );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index a537445d401df4ef4cc32fe428ec8ecaf2c41f3e..95cace2f3ef91d609a4bb3ae196504e9178a3b45 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1141,6 +1141,15 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
 #if JVET_AA0061_IBC_MBVD
   ("IBCMBVD",                                         m_ibcMbvd,                                         true, "IBC MMVD mode (0:off, 1:on)  [default: on]" )
 #endif
+#if JVET_AC0112_IBC_CIIP
+  ("IBCCIIP",                                         m_ibcCiip,                                         true, "IBC CIIP mode (0:off, 1:on)  [default: on]" )
+#endif
+#if JVET_AC0112_IBC_GPM
+  ("IBCGPM",                                          m_ibcGpm,                                          true, "IBC GPM mode (0:off, 1:on)  [default: on]" )
+#endif
+#if JVET_AC0112_IBC_LIC
+  ("IBCLIC",                                          m_ibcLic,                                          true, "IBC LIC mode (0:off, 1:on)  [default: on]" )
+#endif
 
   ("WrapAround",                                      m_wrapAround,                                     false, "Enable horizontal wrap-around motion compensation for inter prediction (0:off, 1:on)  [default: off]")
   ("WrapAroundOffset",                                m_wrapAroundOffset,                                  0u, "Offset in luma samples used for computing the horizontal wrap-around position")
@@ -5153,6 +5162,15 @@ void EncAppCfg::xPrintParameter()
     msg(VERBOSE, "IBC:%d ", m_IBCMode);
 #if JVET_AA0061_IBC_MBVD
     msg( VERBOSE, "IBCMBVD:%d ", m_ibcMbvd );
+#endif
+#if JVET_AC0112_IBC_CIIP
+  msg( VERBOSE, "IBCCIIP:%d ", m_ibcCiip);
+#endif
+#if JVET_AC0112_IBC_GPM
+  msg( VERBOSE, "IBCGPM:%d ", m_ibcGpm);
+#endif
+#if JVET_AC0112_IBC_LIC
+  msg( VERBOSE, "IBCLIC:%d ", m_ibcLic );
 #endif
   msg( VERBOSE, "HashME:%d ", m_HashME );
   msg( VERBOSE, "WrapAround:%d ", m_wrapAround);
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index b3f1559ad6b8fe10ffc727d36a52fdf9c85f2dbf..fae85801d2a3fa7bd6e96696e55710aad473574c 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -500,6 +500,15 @@ protected:
 #if JVET_AA0061_IBC_MBVD
   bool      m_ibcMbvd;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  bool     m_ibcCiip;
+#endif
+#if JVET_AC0112_IBC_GPM
+  bool      m_ibcGpm;
+#endif
+#if JVET_AC0112_IBC_LIC
+  bool      m_ibcLic;
+#endif
 
   bool      m_wrapAround;
   unsigned  m_wrapAroundOffset;
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 514903ab8c5c73f3a9fd1706c6a36ab0eb3dc8e8..9bbbae37b9860782e961431b9bd0ac27291b67c1 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -1047,7 +1047,11 @@ static const int GEO_MAX_NUM_UNI_CANDS =                            6;
 #if JVET_Y0065_GPM_INTRA
 static const int GEO_MAX_NUM_INTRA_CANDS =                          3;
 static const int GEO_NUM_INTRA_RDO_BUFFER =                         23;
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+static const int GEO_NUM_RDO_BUFFER =                               GEO_MAX_NUM_UNI_CANDS + 67;
+#else
 static const int GEO_NUM_RDO_BUFFER =                               GEO_MAX_NUM_UNI_CANDS + GEO_NUM_INTRA_RDO_BUFFER;
+#endif
 static const int GEO_MAX_NUM_CANDS = (GEO_MAX_NUM_UNI_CANDS+GEO_MAX_NUM_INTRA_CANDS) * ((GEO_MAX_NUM_UNI_CANDS+GEO_MAX_NUM_INTRA_CANDS) - 1);
 #else
 static const int GEO_MAX_NUM_CANDS = GEO_MAX_NUM_UNI_CANDS * (GEO_MAX_NUM_UNI_CANDS - 1);
@@ -1150,6 +1154,20 @@ static const int IBC_MBVD_NUM = IBC_MBVD_BASE_NUM * IBC_MBVD_MAX_REFINE_NUM;
 static const int IBC_MBVD_SIZE_ENC =                                 8;
 static const int ADAPTIVE_SUB_GROUP_SIZE_IBC_MBVD = IBC_MBVD_MAX_REFINE_NUM;
 #endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+static const int IBC_GPM_MAX_NUM_UNI_CANDS =                        15;
+#endif
+#if JVET_AC0112_IBC_CIIP
+static const int IBC_CIIP_MAX_NUM_INTRA_CANDS =                      2;
+#endif
+#if JVET_AC0112_IBC_GPM
+static const int IBC_GPM_MAX_NUM_INTRA_CANDS =                       3;
+static const int IBC_GPM_MAX_TRY_WEIGHTED_SAD =                     36;
+static const int IBC_GPM_MAX_TRY_WEIGHTED_SATD =                    20;
+static const int IBC_GPM_MAX_SPLIT_DIR_FIRST_SET_NUM =               8;
+static const int IBC_GPM_MAX_SPLIT_DIR_SECOND_SET_NUM =             40;
+static const int IBC_GPM_NUM_BLENDING =                              1; // 1 or 5
+#endif
 static constexpr int MV_EXPONENT_BITCOUNT    = 4;
 static constexpr int MV_MANTISSA_BITCOUNT    = 6;
 static constexpr int MV_MANTISSA_UPPER_LIMIT = ((1 << (MV_MANTISSA_BITCOUNT - 1)) - 1);
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index aaf3f2b64bb129cd347295370129cce5497327c5..1ff03737a41e4769938c43cb5d78036c0e7bf947 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -532,6 +532,9 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
     pu.addHypData.clear();
     pu.numMergedAddHyps = 0;
 #endif
+#if JVET_AC0112_IBC_LIC
+    pu.cu->ibcLicFlag = ibcLicFlags[candIdx];
+#endif
 #if JVET_AA0070_RRIBC
     pu.cu->rribcFlipType = rribcFlipTypes[candIdx];
   }
@@ -1426,6 +1429,9 @@ bool MergeCtx::setIbcMbvdMergeCandiInfo(PredictionUnit& pu, int candIdx, int can
   pu.bv = pu.mv[REF_PIC_LIST_0];
   pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); // used for only integer resolution
   pu.cu->imv = pu.cu->imv == IMV_HPEL ? 0 : pu.cu->imv;
+#if JVET_AC0112_IBC_LIC
+  pu.cu->ibcLicFlag = ibcLicFlags[fPosBaseIdx];
+#endif
 #if JVET_AA0070_RRIBC
   pu.cu->rribcFlipType = rribcFlipTypes[fPosBaseIdx];
 #endif
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index db3638d8952c44c4f1ee8cfd72bc9fd81dc72df3..2b5c4ec0061402659a9e3d27424a2c0d044764b0 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -561,6 +561,9 @@ public:
 #if INTER_LIC
   bool          LICFlags[NUM_MERGE_CANDS];
 #endif
+#if JVET_AC0112_IBC_LIC
+  bool          ibcLicFlags[NUM_MERGE_CANDS];
+#endif
 #if JVET_AA0070_RRIBC
   int       rribcFlipTypes[NUM_MERGE_CANDS];
 #endif
@@ -578,6 +581,9 @@ public:
 #if INTER_LIC
   bool          LICFlags          [ MRG_MAX_NUM_CANDS      ];
 #endif
+#if JVET_AC0112_IBC_LIC
+  bool          ibcLicFlags       [ MRG_MAX_NUM_CANDS      ];
+#endif
 #if JVET_AA0070_RRIBC
   int rribcFlipTypes[MRG_MAX_NUM_CANDS];
 #endif
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 4323ce25f33ca8745c3f26e87230195a75ff15c5..116ce868b66744364b5cdc1a0c4aba523e55f713 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -2877,6 +2877,117 @@ const CtxSet ContextSetCfg::IBCFlag = ContextSetCfg::addCtxSet
   { 147, 117, 146, },
   });
 
+#if JVET_AC0112_IBC_CIIP
+const CtxSet ContextSetCfg::IbcCiipFlag = ContextSetCfg::addCtxSet
+({
+  {  CNU, CNU, CNU, },
+  {  CNU, CNU, CNU, },
+  {  CNU, CNU, CNU, },
+  {  DWS, DWS, DWS, },
+  {  DWS, DWS, DWS, },
+  {  DWS, DWS, DWS, },
+  {  DWE, DWE, DWE, },
+  {  DWE, DWE, DWE, },
+  {  DWE, DWE, DWE, },
+  {  DWO, DWO, DWO, },
+  {  DWO, DWO, DWO, },
+  });
+
+const CtxSet ContextSetCfg::IbcCiipIntraIdx = ContextSetCfg::addCtxSet
+({
+  {  CNU, },
+  {  CNU, },
+  {  CNU, },
+  {  DWS, },
+  {  DWS, },
+  {  DWS, },
+  {  DWE, },
+  {  DWE, },
+  {  DWE, },
+  {  DWO, },
+  {  DWO, },
+  });
+#endif
+
+#if JVET_AC0112_IBC_GPM
+const CtxSet ContextSetCfg::IbcGpmFlag = ContextSetCfg::addCtxSet
+({
+  { CNU, },
+  { CNU, },
+  { CNU, },
+  { DWS, },
+  { DWS, },
+  { DWS, },
+  { DWE, },
+  { DWE, },
+  { DWE, },
+  { DWO, },
+  { DWO, },
+  });
+
+const CtxSet ContextSetCfg::IbcGpmIntraFlag = ContextSetCfg::addCtxSet
+({
+  { CNU, },
+  { CNU, },
+  { CNU, },
+  { DWS, },
+  { DWS, },
+  { DWS, },
+  { DWE, },
+  { DWE, },
+  { DWE, },
+  { DWO, },
+  { DWO, },
+  });
+
+const CtxSet ContextSetCfg::IbcGpmSplitDirSetFlag = ContextSetCfg::addCtxSet
+({
+  { CNU, },
+  { CNU, },
+  { CNU, },
+  { DWS, },
+  { DWS, },
+  { DWS, },
+  { DWE, },
+  { DWE, },
+  { DWE, },
+  { DWO, },
+  { DWO, },
+  });
+
+const CtxSet ContextSetCfg::IbcGpmBldIdx = ContextSetCfg::addCtxSet
+({
+  { CNU, CNU, CNU, CNU },
+  { CNU, CNU, CNU, CNU },
+  { CNU, CNU, CNU, CNU },
+  { DWS, DWS, DWS, DWS },
+  { DWS, DWS, DWS, DWS },
+  { DWS, DWS, DWS, DWS },
+  { DWE, DWE, DWE, DWE },
+  { DWE, DWE, DWE, DWE },
+  { DWE, DWE, DWE, DWE },
+  { DWO, DWO, DWO, DWO },
+  { DWO, DWO, DWO, DWO },
+});
+#endif
+
+#if JVET_AC0112_IBC_LIC
+const CtxSet ContextSetCfg::IbcLicFlag = ContextSetCfg::addCtxSet
+({
+  { CNU, },
+  { CNU, },
+  { CNU, },
+  { DWS, },
+  { DWS, },
+  { DWS, },
+  { DWE, },
+  { DWE, },
+  { DWE, },
+  { DWO, },
+  { DWO, },
+  });
+#endif
+
 const CtxSet ContextSetCfg::JointCbCrFlag = ContextSetCfg::addCtxSet
 ({
   {  34,  28,  52, },
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index 273af587963943a9d42f89d37175d0e2efd66fb7..0d7706c399bef38d0d0c4b3ff5cfafa99c0c35aa 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -413,6 +413,19 @@ public:
   static const CtxSet   IbcMbvdMergeIdx;
   static const CtxSet   IbcMbvdStepMvpIdx;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  static const CtxSet   IbcCiipFlag;
+  static const CtxSet   IbcCiipIntraIdx;
+#endif
+#if JVET_AC0112_IBC_GPM
+  static const CtxSet   IbcGpmFlag;
+  static const CtxSet   IbcGpmIntraFlag;
+  static const CtxSet   IbcGpmSplitDirSetFlag;
+  static const CtxSet   IbcGpmBldIdx;
+#endif
+#if JVET_AC0112_IBC_LIC
+  static const CtxSet   IbcLicFlag;
+#endif
 
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   static const CtxSet   TMMergeFlag;
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index d5937ae5dd41fecb3010bad155f777fe778fb0b5..1f166a441f8b97dc13b5b85cbfae29cec848a484 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -2281,6 +2281,25 @@ void InterPrediction::xPredInterBlk ( const ComponentID& compID, const Predictio
       m_predictionBeforeLIC.bufs[compID].copyFrom( dstBuf );
     }
 
+#if JVET_AC0112_IBC_LIC
+#if JVET_AC0112_IBC_GPM && JVET_AC0112_IBC_CIIP
+  if (pu.cu->ibcLicFlag && !pu.ibcCiipFlag && !pu.ibcGpmFlag)
+#else
+#if JVET_AC0112_IBC_CIIP
+  if (pu.cu->ibcLicFlag && !pu.ibcCiipFlag)
+#else
+#if JVET_AC0112_IBC_GPM
+  if (pu.cu->ibcLicFlag && !pu.ibcGpmFlag)
+#else
+  if (pu.cu->ibcLicFlag)
+#endif
+#endif
+#endif
+  {
+    xLocalIlluComp(pu, compID, pu.bv, dstBuf);
+  }
+#endif
+
 #if JVET_W0090_ARMC_TM || JVET_Z0056_GPM_SPLIT_MODE_REORDERING
     if (pu.cu->LICFlag && (!pu.ciipFlag || doLic))
 #else
@@ -4024,10 +4043,50 @@ void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBu
     {
       CHECK(!luma, "IBC only for Chroma is not allowed.");
       xIntraBlockCopy(pu, predBuf, COMPONENT_Y);
+#if JVET_AC0112_IBC_LIC
+#if JVET_AC0112_IBC_GPM && JVET_AC0112_IBC_CIIP
+      if (pu.cu->ibcLicFlag && !pu.ibcCiipFlag && !pu.ibcGpmFlag)
+#else
+#if JVET_AC0112_IBC_CIIP
+      if (pu.cu->ibcLicFlag && !pu.ibcCiipFlag)
+#else
+#if JVET_AC0112_IBC_GPM
+      if (pu.cu->ibcLicFlag && !pu.ibcGpmFlag)
+#else
+      if (pu.cu->ibcLicFlag)
+#endif
+#endif
+#endif
+      {
+        PelBuf dstBuf = predBuf.Y();
+        xLocalIlluComp(pu, COMPONENT_Y, pu.bv, dstBuf);
+      }
+#endif
       if (chroma && isChromaEnabled(pu.chromaFormat))
       {
         xIntraBlockCopy(pu, predBuf, COMPONENT_Cb);
         xIntraBlockCopy(pu, predBuf, COMPONENT_Cr);
+#if JVET_AC0112_IBC_LIC
+#if JVET_AC0112_IBC_GPM && JVET_AC0112_IBC_CIIP
+        if (pu.cu->ibcLicFlag && !pu.ibcCiipFlag && !pu.ibcGpmFlag)
+#else
+#if JVET_AC0112_IBC_CIIP
+        if (pu.cu->ibcLicFlag && !pu.ibcCiipFlag)
+#else
+#if JVET_AC0112_IBC_GPM
+        if (pu.cu->ibcLicFlag && !pu.ibcGpmFlag)
+#else
+        if (pu.cu->ibcLicFlag)
+#endif
+#endif
+#endif
+        {
+          PelBuf dstBufCb = predBuf.Cb();
+          xLocalIlluComp(pu, COMPONENT_Cb, pu.bv, dstBufCb);
+          PelBuf dstBufCr = predBuf.Cr();
+          xLocalIlluComp(pu, COMPONENT_Cr, pu.bv, dstBufCr);
+        }
+#endif
       }
       return;
     }
@@ -5061,6 +5120,182 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
   }
 }
 
+#if JVET_AC0112_IBC_GPM
+void InterPrediction::motionCompensationIbcGpm( CodingUnit &cu, MergeCtx &ibcGpmMrgCtx, IntraPrediction* pcIntraPred)
+{
+  if ((int)(cu.firstPU->ibcGpmMergeIdx0)-IBC_GPM_MAX_NUM_UNI_CANDS > 0 || (int)(cu.firstPU->ibcGpmMergeIdx1)-IBC_GPM_MAX_NUM_UNI_CANDS > 0)
+  {
+    pcIntraPred->deriveDimdMode(cu.cs->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+    cu.timdMode = pcIntraPred->deriveTimdMode(cu.cs->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+  }
+
+  const uint8_t splitDir = cu.firstPU->ibcGpmSplitDir;
+  const uint8_t candIdx0 = cu.firstPU->ibcGpmMergeIdx0;
+  const uint8_t candIdx1 = cu.firstPU->ibcGpmMergeIdx1;
+  const uint8_t bldIdx = cu.firstPU->ibcGpmBldIdx;
+
+  for( auto &pu : CU::traversePUs( cu ) )
+  {
+    const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, pu.lwidth(), pu.lheight() ) );
+    PelUnitBuf tmpGeoBuf0 = m_geoPartBuf[0].getBuf( localUnitArea );
+    PelUnitBuf tmpGeoBuf1 = m_geoPartBuf[1].getBuf( localUnitArea );
+    PelUnitBuf predBuf    = cu.cs->getPredBuf( pu );
+    const bool luma = cu.Y().valid();
+    const bool chroma = isChromaEnabled(cu.chromaFormat) && cu.Cb().valid();
+    int orgMergeIdx = pu.mergeIdx;
+
+    bool isIntra0 = candIdx0 >= IBC_GPM_MAX_NUM_UNI_CANDS;
+    bool isIntra1 = candIdx1 >= IBC_GPM_MAX_NUM_UNI_CANDS;
+    if (isIntra0)
+    {
+      PU::getGeoIntraMPMs(pu, pu.intraMPM, splitDir, g_geoTmShape[0][g_GeoParams[pu.ibcGpmSplitDir][0]]);
+      pu.intraDir[0] = pu.intraMPM[candIdx0 - IBC_GPM_MAX_NUM_UNI_CANDS];
+      pcIntraPred->initIntraPatternChType(cu, pu.Y());
+      pcIntraPred->predIntraAng(COMPONENT_Y, tmpGeoBuf0.Y(), pu);
+      pu.intraDir[0] = DC_IDX;
+      pu.intraDir[1] = PLANAR_IDX;
+      if (chroma)
+      {
+        pu.intraDir[1] = pu.intraMPM[candIdx0 - IBC_GPM_MAX_NUM_UNI_CANDS];
+        pcIntraPred->initIntraPatternChType(cu, pu.Cb());
+        pcIntraPred->predIntraAng(COMPONENT_Cb, tmpGeoBuf0.Cb(), pu);
+        pcIntraPred->initIntraPatternChType(cu, pu.Cr());
+        pcIntraPred->predIntraAng(COMPONENT_Cr, tmpGeoBuf0.Cr(), pu);
+        pu.intraDir[1] = PLANAR_IDX;
+      }
+    }
+    else
+    {
+      ibcGpmMrgCtx.setMergeInfo( pu, candIdx0 );
+      if (pu.tmMergeFlag)
+      {
+        deriveTMMv(pu);
+        pu.bv = pu.mv[0];
+        pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
+      }
+      if (luma && (chroma || !isChromaEnabled(cu.chromaFormat)))
+      {
+        motionCompensation(pu, tmpGeoBuf0, REF_PIC_LIST_X, true, true);
+      }
+      else
+      {
+        motionCompensation(pu, tmpGeoBuf0, REF_PIC_LIST_X, true, chroma);
+      }
+    }
+
+    if (isIntra1)
+    {
+      PU::getGeoIntraMPMs(pu, pu.intraMPM+GEO_MAX_NUM_INTRA_CANDS, splitDir, g_geoTmShape[1][g_GeoParams[pu.ibcGpmSplitDir][0]]);
+      pu.intraDir[0] = pu.intraMPM[candIdx1 - IBC_GPM_MAX_NUM_UNI_CANDS + GEO_MAX_NUM_INTRA_CANDS];
+      pcIntraPred->initIntraPatternChType(cu, pu.Y());
+      pcIntraPred->predIntraAng(COMPONENT_Y, tmpGeoBuf1.Y(), pu);
+      pu.intraDir[0] = DC_IDX;
+      pu.intraDir[1] = PLANAR_IDX;
+      if (chroma)
+      {
+        pu.intraDir[1] = pu.intraMPM[candIdx1 - IBC_GPM_MAX_NUM_UNI_CANDS + GEO_MAX_NUM_INTRA_CANDS];
+        pcIntraPred->initIntraPatternChType(cu, pu.Cb());
+        pcIntraPred->predIntraAng(COMPONENT_Cb, tmpGeoBuf1.Cb(), pu);
+        pcIntraPred->initIntraPatternChType(cu, pu.Cr());
+        pcIntraPred->predIntraAng(COMPONENT_Cr, tmpGeoBuf1.Cr(), pu);
+        pu.intraDir[1] = PLANAR_IDX;
+      }
+    }
+    else
+    {
+      ibcGpmMrgCtx.setMergeInfo( pu, candIdx1 );
+      if (pu.tmMergeFlag)
+      {
+        deriveTMMv(pu);
+        pu.bv = pu.mv[0];
+        pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
+      }
+      if (luma && (chroma || !isChromaEnabled(cu.chromaFormat)))
+      {
+        motionCompensation(pu, tmpGeoBuf1, REF_PIC_LIST_X, true, true);
+      }
+      else
+      {
+        motionCompensation(pu, tmpGeoBuf1, REF_PIC_LIST_X, true, chroma);
+      }
+    }
+
+#if JVET_AA0058_GPM_ADP_BLD
+    weightedGeoBlkRounded(pu, splitDir, bldIdx, CHANNEL_TYPE_LUMA, predBuf, tmpGeoBuf0, tmpGeoBuf1);
+    if (chroma)
+    {
+      weightedGeoBlkRounded(pu, splitDir, bldIdx, CHANNEL_TYPE_CHROMA, predBuf, tmpGeoBuf0, tmpGeoBuf1);
+    }
+#else
+    weightedGeoBlk(pu, splitDir, isChromaEnabled(pu.chromaFormat)? MAX_NUM_CHANNEL_TYPE : CHANNEL_TYPE_LUMA, predBuf, tmpGeoBuf0, tmpGeoBuf1);
+#endif
+    pu.mergeIdx = orgMergeIdx;
+    ibcGpmMrgCtx.setMergeInfo( pu, pu.mergeIdx );
+    if (pu.tmMergeFlag)
+    {
+      deriveTMMv(pu);
+      pu.bv = pu.mv[0];
+      pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
+    }
+    pu.intraDir[0] = DC_IDX;
+    pu.intraDir[1] = PLANAR_IDX;
+  }
+}
+
+#if JVET_AA0070_RRIBC
+void  InterPrediction::adjustIbcMergeRribcCand(PredictionUnit &pu, MergeCtx& mrgCtx, uint32_t startPos, uint32_t endPos)
+{
+  if (mrgCtx.numValidMergeCand <= 1)
+  {
+    return;
+  }
+
+  uint32_t rdCandList[IBC_MRG_MAX_NUM_CANDS_MEM];
+  Distortion candCostList[IBC_MRG_MAX_NUM_CANDS_MEM];
+
+  for (uint32_t i = 0; i < IBC_MRG_MAX_NUM_CANDS_MEM; i++)
+  {
+    rdCandList[i] = i;
+    candCostList[i] = MAX_UINT;
+  }
+
+  Distortion uiCost;
+  int candNumNoRribc = 0;
+  bool noNeedSort = true;
+  for (uint32_t uiMergeCand = startPos; uiMergeCand < endPos; ++uiMergeCand)
+  {
+    uiCost = 0;
+    if (mrgCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].mv.hor == 0 && mrgCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].mv.ver == 0)
+    {
+      break;
+    }
+    if (candNumNoRribc >= mrgCtx.numValidMergeCand)
+    {
+      break;
+    }
+    if (mrgCtx.rribcFlipTypes[uiMergeCand] > 0)
+    {
+      uiCost = MAX_UINT - 1;
+      if (noNeedSort && uiMergeCand < mrgCtx.numValidMergeCand)
+      {
+        noNeedSort = false;
+      }
+    }
+    else
+    {
+      candNumNoRribc++;
+      uiCost = uiMergeCand;
+    }
+    updateCandList(uiMergeCand, uiCost, IBC_MRG_MAX_NUM_CANDS_MEM, rdCandList, candCostList);
+  }
+  if (!noNeedSort)
+  {
+    updateIBCCandInfo(pu, mrgCtx, rdCandList, startPos, endPos);
+  }
+}
+#endif
+#endif
+
 #if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
 void InterPrediction::getBestGeoTMModeList(PredictionUnit &pu, uint8_t& numValidInList, uint8_t(&modeList)[GEO_NUM_SIG_PARTMODE], Pel* (&pRefTopPart0)[GEO_NUM_TM_MV_CAND], Pel* (&pRefLeftPart0)[GEO_NUM_TM_MV_CAND], Pel* (&pRefTopPart1)[GEO_NUM_TM_MV_CAND], Pel* (&pRefLeftPart1)[GEO_NUM_TM_MV_CAND])
@@ -6109,7 +6344,11 @@ bool InterPrediction::xAMLIBCGetCurBlkTemplate(PredictionUnit& pu, int nCurBlkWi
   return true;
 }
 
+#if JVET_AC0112_IBC_LIC
+void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth, int nCurBlkHeight, bool doIbcLic)
+#else
 void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth, int nCurBlkHeight)
+#endif
 {
   Mv mvCurr;
   mvCurr = pu.bv;
@@ -6119,6 +6358,247 @@ void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth,
   const Picture&  currPic = *pu.cs->picture;
   const CPelBuf recBuf = currPic.getRecoBuf(pu.cs->picture->blocks[COMPONENT_Y]);
   /* std::vector<Pel>& invLUT = m_pcReshape->getInvLUT();*/
+#if JVET_AC0112_IBC_LIC
+  Pel* refLeftTemplate  = m_pcLICRefLeftTemplate;
+  Pel* refAboveTemplate = m_pcLICRefAboveTemplate;
+  Pel* recLeftTemplate  = m_pcLICRecLeftTemplate;
+  Pel* recAboveTemplate = m_pcLICRecAboveTemplate;
+  int numTemplate[2] = { 0 , 0 }; // 0:Above, 1:Left
+  const int bitDepth = pu.cs->sps->getBitDepth(toChannelType(COMPONENT_Y));
+  const int precShift = std::max(0, bitDepth - 12);
+  const ClpRng& clpRng = pu.cu->cs->slice->clpRng(COMPONENT_Y);
+  int shift = 0, scale = 0, offset = 0;
+  Mv mvTop(0, -AML_MERGE_TEMPLATE_SIZE);
+  Mv mvLeft(-AML_MERGE_TEMPLATE_SIZE, 0);
+  if (m_bAMLTemplateAvailabe[0])
+  {
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 2)
+    {
+      mvTop.setVer(nCurBlkHeight);
+    }
+#endif
+    mvTop += mvCurr;
+
+    MotionInfo miTop;
+    miTop.mv[0] = Mv(mvTop.hor <<horShift , mvTop.ver<< verShift);
+    miTop.refIdx[0] = MAX_NUM_REF;
+    Mv mvTop2(0, -1);
+    mvTop2 += mvTop;
+    MotionInfo miTop2;
+    miTop2.mv[0] = Mv(mvTop2.hor <<horShift , mvTop2.ver<< verShift);
+    miTop2.refIdx[0] = MAX_NUM_REF;
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 2)
+    {
+      if (!PU::checkIsIBCCandidateValid(pu, miTop, true, true))
+      {
+        mvTop.setVer(mvCurr.getVer() + nCurBlkHeight - AML_MERGE_TEMPLATE_SIZE);
+      }
+    }
+    else
+#endif
+    if (!PU::checkIsIBCCandidateValid(pu, miTop, true, true))
+    {
+      mvTop = mvCurr;
+    }
+#if JVET_AA0070_RRIBC
+    else if (doIbcLic && pu.cu->ibcLicFlag && pu.cu->rribcFlipType == 0 && PU::checkIsIBCCandidateValid(pu, miTop2, true, true))
+#else
+    else if (doIbcLic && pu.cu->ibcLicFlag && PU::checkIsIBCCandidateValid(pu, miTop2, true, true))
+#endif
+    {
+      xGetIbcLicPredBlkTpl<true>(*pu.cu, COMPONENT_Y, recBuf, mvTop, 0, 0, nCurBlkWidth, refAboveTemplate);
+      const Pel* rec2 = recBuf.bufAt(pu.blocks[COMPONENT_Y].pos().offset(0, -2));
+      for (int k = 0; k < nCurBlkWidth; k++)
+      {
+        int refVal = refAboveTemplate[k];
+        int recVal = rec2[k];
+        recVal >>= precShift;
+        refVal >>= precShift;
+        refAboveTemplate[k] = refVal;
+        recAboveTemplate[k] = recVal;
+        numTemplate[0]++;
+      }
+    }
+  }
+  if (m_bAMLTemplateAvailabe[1])
+  {
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 1)
+    {
+      mvLeft.setHor(nCurBlkWidth);
+    }
+#endif
+    mvLeft += mvCurr;
+
+    MotionInfo miLeft;
+    miLeft.mv[0] = Mv(mvLeft.hor <<horShift , mvLeft.ver<< verShift);
+    miLeft.refIdx[0] = MAX_NUM_REF;
+    Mv mvLeft2(-1, 0);
+    mvLeft2 += mvLeft;
+    MotionInfo miLeft2;
+    miLeft2.mv[0] = Mv(mvLeft2.hor <<horShift , mvLeft2.ver<< verShift);
+    miLeft2.refIdx[0] = MAX_NUM_REF;
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 1)
+    {
+      if (!PU::checkIsIBCCandidateValid(pu, miLeft, true, false))
+      {
+         mvLeft.setHor(mvCurr.getHor() + nCurBlkWidth - AML_MERGE_TEMPLATE_SIZE);
+      }
+    }
+    else
+#endif
+    if (!PU::checkIsIBCCandidateValid(pu, miLeft, true, false))
+    {
+      mvLeft = mvCurr;
+    }
+#if JVET_AA0070_RRIBC
+    else if (doIbcLic && pu.cu->ibcLicFlag && pu.cu->rribcFlipType == 0 && PU::checkIsIBCCandidateValid(pu, miLeft2, true, false))
+#else
+    else if (doIbcLic && pu.cu->ibcLicFlag && PU::checkIsIBCCandidateValid(pu, miLeft2, true, false))
+#endif
+    {
+      xGetIbcLicPredBlkTpl<false>(*pu.cu, COMPONENT_Y, recBuf, mvLeft, 0, 0, nCurBlkHeight, refLeftTemplate);
+      const Pel* rec2 = recBuf.bufAt(pu.blocks[COMPONENT_Y].pos().offset(-2, 0));
+      for (int k = 0; k < nCurBlkHeight; k++)
+      {
+        int refVal = refLeftTemplate[k];
+        int recVal = rec2[recBuf.stride * k];
+        recVal >>= precShift;
+        refVal >>= precShift;
+        refLeftTemplate[k] = refVal;
+        recLeftTemplate[k] = recVal;
+        numTemplate[1]++;
+      }
+    }
+  }
+  if (numTemplate[0] + numTemplate[1] > 0)
+  {
+    xGetLICParamGeneral(*pu.cu, COMPONENT_Y, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate, shift, scale, offset);
+  }
+  if (m_bAMLTemplateAvailabe[0])
+  {
+    const Pel*    rec = recBuf.bufAt(pu.blocks[COMPONENT_Y].pos().offset(mvTop.hor, mvTop.ver));
+    PelBuf pcYBuf = PelBuf(m_acYuvRefAMLTemplate[0][0], nCurBlkWidth, AML_MERGE_TEMPLATE_SIZE);
+    Pel*   pcY = pcYBuf.bufAt(0, 0);
+    if (numTemplate[0] + numTemplate[1] > 0)
+    {
+      for (int k = 0; k < nCurBlkWidth; k++)
+      {
+        for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
+        {
+#if JVET_AA0070_RRIBC
+          int recVal;
+          if (pu.cu->rribcFlipType == 0)
+          {
+            recVal = rec[k + l * recBuf.stride];
+          }
+          else if (pu.cu->rribcFlipType == 1)
+          {
+            recVal = rec[nCurBlkWidth - 1 - k + l * recBuf.stride];
+          }
+          else
+          {
+            recVal = rec[k + (AML_MERGE_TEMPLATE_SIZE - 1 - l) * recBuf.stride];
+          }
+#else
+          int recVal = rec[k + l * recBuf.stride];
+#endif
+          pcY[k + l * nCurBlkWidth] = ClipPel(((recVal * scale) >> shift) + offset, clpRng);
+        }
+      }
+    }
+    else
+    {
+      for (int k = 0; k < nCurBlkWidth; k++)
+      {
+        for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
+        {
+#if JVET_AA0070_RRIBC
+          int recVal;
+          if (pu.cu->rribcFlipType == 0)
+          {
+            recVal = rec[k + l * recBuf.stride];
+          }
+          else if (pu.cu->rribcFlipType == 1)
+          {
+            recVal = rec[nCurBlkWidth - 1 - k + l * recBuf.stride];
+          }
+          else
+          {
+            recVal = rec[k + (AML_MERGE_TEMPLATE_SIZE - 1 - l) * recBuf.stride];
+          }
+#else
+          int recVal = rec[k + l * recBuf.stride];
+#endif
+          pcY[k + l * nCurBlkWidth] = recVal;
+        }
+      }
+    }
+  }
+  if (m_bAMLTemplateAvailabe[1])
+  {
+    PelBuf pcYBuf = PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nCurBlkHeight);
+    Pel*   pcY = pcYBuf.bufAt(0, 0);
+    const Pel*    rec = recBuf.bufAt(pu.blocks[COMPONENT_Y].pos().offset( mvLeft.hor,  mvLeft.ver));
+    if (numTemplate[0] + numTemplate[1] > 0)
+    {
+      for (int k = 0; k < nCurBlkHeight; k++)
+      {
+        for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
+        {
+#if JVET_AA0070_RRIBC
+          int recVal;
+          if (pu.cu->rribcFlipType == 0)
+          {
+            recVal = rec[recBuf.stride * k + l];
+          }
+          else if (pu.cu->rribcFlipType == 1)
+          {
+            recVal = rec[recBuf.stride * k + AML_MERGE_TEMPLATE_SIZE - 1 - l];
+          }
+          else
+          {
+            recVal = rec[recBuf.stride * (nCurBlkHeight - 1 - k) + l];
+          }
+#else
+          int recVal = rec[recBuf.stride * k + l];
+#endif
+          pcY[AML_MERGE_TEMPLATE_SIZE * k + l] = ClipPel(((recVal * scale) >> shift) + offset, clpRng);
+        }
+      }
+    }
+    else
+    {
+      for (int k = 0; k < nCurBlkHeight; k++)
+      {
+        for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
+        {
+#if JVET_AA0070_RRIBC
+          int recVal;
+          if (pu.cu->rribcFlipType == 0)
+          {
+            recVal = rec[recBuf.stride * k + l];
+          }
+          else if (pu.cu->rribcFlipType == 1)
+          {
+            recVal = rec[recBuf.stride * k + AML_MERGE_TEMPLATE_SIZE - 1 - l];
+          }
+          else
+          {
+            recVal = rec[recBuf.stride * (nCurBlkHeight - 1 - k) + l];
+          }
+#else
+          int recVal = rec[recBuf.stride * k + l];
+#endif
+          pcY[AML_MERGE_TEMPLATE_SIZE * k + l] = recVal;
+        }
+      }
+    }
+  }
+#else
   if (m_bAMLTemplateAvailabe[0])
   {
     Mv mvTop(0, -AML_MERGE_TEMPLATE_SIZE);
@@ -6232,6 +6712,7 @@ void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth,
       }
     }
   }
+#endif
 }
 #endif
 
@@ -9237,6 +9718,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
 #if INTER_LIC
     mrgCtxTmp.LICFlags[ui] = false;
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtxTmp.ibcLicFlags[ui] = false;
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtxTmp.rribcFlipTypes[ui] = 0;
 #endif
@@ -9262,6 +9746,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
 #if INTER_LIC 
     mrgCtxTmp.LICFlags[uiMergeCand] = mrgCtx.LICFlags[uiMergeCand];
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtxTmp.ibcLicFlags[uiMergeCand] = mrgCtx.ibcLicFlags[uiMergeCand];
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtxTmp.rribcFlipTypes[uiMergeCand] = mrgCtx.rribcFlipTypes[uiMergeCand];
 #endif
@@ -9288,6 +9775,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
 #if INTER_LIC
     mrgCtx.LICFlags[uiMergeCand] = mrgCtxTmp.LICFlags[RdCandList[uiMergeCand / ADAPTIVE_IBC_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_IBC_SUB_GROUP_SIZE]];
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[uiMergeCand] = mrgCtxTmp.ibcLicFlags[RdCandList[uiMergeCand / ADAPTIVE_IBC_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_IBC_SUB_GROUP_SIZE]];
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtx.rribcFlipTypes[uiMergeCand] = mrgCtxTmp.rribcFlipTypes[RdCandList[uiMergeCand / ADAPTIVE_IBC_SUB_GROUP_SIZE][uiMergeCand % ADAPTIVE_IBC_SUB_GROUP_SIZE]];
 #endif
@@ -9345,7 +9835,15 @@ void  InterPrediction::adjustIBCMergeCandidates(PredictionUnit &pu, MergeCtx& mr
     PelBuf pcBufPredRefLeft = PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight);
     PelBuf pcBufPredCurLeft = PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight);
 
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0061_IBC_MBVD
+    getIBCAMLRefTemplate(pu, nWidth, nHeight, !pu.ibcMbvdMergeFlag);
+#else
+    getIBCAMLRefTemplate(pu, nWidth, nHeight, true);
+#endif
+#else
     getIBCAMLRefTemplate(pu, nWidth, nHeight);
+#endif
 
     if (m_bAMLTemplateAvailabe[0])
     {
@@ -9379,6 +9877,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
 #if INTER_LIC
     mrgCtxTmp.LICFlags[ui] = false;
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtxTmp.ibcLicFlags[ui] = false;
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtxTmp.rribcFlipTypes[ui] = 0;
 #endif
@@ -9398,6 +9899,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
 #if INTER_LIC 
     mrgCtxTmp.LICFlags[uiMergeCand] = mrgCtx.LICFlags[uiMergeCand];
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtxTmp.ibcLicFlags[uiMergeCand] = mrgCtx.ibcLicFlags[uiMergeCand];
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtxTmp.rribcFlipTypes[uiMergeCand] = mrgCtx.rribcFlipTypes[uiMergeCand];
 #endif
@@ -9418,6 +9922,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
 #if INTER_LIC
     mrgCtx.LICFlags[uiMergeCand] = mrgCtxTmp.LICFlags[RdCandList[uiMergeCand -startPos]];
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[uiMergeCand] = mrgCtxTmp.ibcLicFlags[RdCandList[uiMergeCand -startPos]];
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtx.rribcFlipTypes[uiMergeCand] = mrgCtxTmp.rribcFlipTypes[RdCandList[uiMergeCand -startPos]];
 #endif
@@ -10899,7 +11406,9 @@ void InterPrediction::xGetSublkTemplate(const CodingUnit& cu,
     }
   }
 }
+#endif
 
+#if INTER_LIC || JVET_AC0112_IBC_LIC
 void InterPrediction::xGetLICParamGeneral(const CodingUnit& cu,
                                           const ComponentID compID,
                                           int*              numTemplate,
@@ -10999,7 +11508,9 @@ void InterPrediction::xGetLICParamGeneral(const CodingUnit& cu,
   offset = (sumY - ((scale * sumX) >> shift) + ((1 << (cntShift)) >> 1)) >> cntShift;
   offset = Clip3(minOffset, maxOffset, offset);
 }
+#endif
 
+#if INTER_LIC
 template <bool trueAfalseL>
 void InterPrediction::xGetPredBlkTpl(const CodingUnit& cu, const ComponentID compID, const CPelBuf& refBuf, const Mv& mv, const int posW, const int posH, const int tplSize, Pel* predBlkTpl
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
@@ -11082,6 +11593,171 @@ void InterPrediction::xGetPredBlkTpl(const CodingUnit& cu, const ComponentID com
 }
 #endif // INTER_LIC
 
+#if JVET_AC0112_IBC_LIC
+void InterPrediction::xLocalIlluComp(const PredictionUnit& pu,
+                                     const ComponentID     compID,
+                                     const Mv&             bv,
+                                     PelBuf&               dstBuf
+)
+{
+  Pel* refLeftTemplate  = m_pcLICRefLeftTemplate;
+  Pel* refAboveTemplate = m_pcLICRefAboveTemplate;
+  Pel* recLeftTemplate  = m_pcLICRecLeftTemplate;
+  Pel* recAboveTemplate = m_pcLICRecAboveTemplate;
+  int numTemplate[2] = { 0 , 0 }; // 0:Above, 1:Left
+  xGetSublkTemplate(*pu.cu, compID, bv, pu.blocks[compID].width, pu.blocks[compID].height, 0, 0, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate);
+
+  int shift = 0, scale = 0, offset = 0;
+  xGetLICParamGeneral(*pu.cu, compID, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate, shift, scale, offset);
+
+  const ClpRng& clpRng = pu.cu->cs->slice->clpRng(compID);
+  dstBuf.linearTransform(scale, shift, offset, true, clpRng);
+}
+
+void InterPrediction::xGetSublkTemplate(const CodingUnit& cu,
+                                        const ComponentID compID,
+                                        const Mv&         bv,
+                                        const int         sublkWidth,
+                                        const int         sublkHeight,
+                                        const int         posW,
+                                        const int         posH,
+                                        int*              numTemplate,
+                                        Pel*              refLeftTemplate,
+                                        Pel*              refAboveTemplate,
+                                        Pel*              recLeftTemplate,
+                                        Pel*              recAboveTemplate
+                                        )
+{
+  const int       bitDepth = cu.cs->sps->getBitDepth(toChannelType(compID));
+  const int       precShift = std::max(0, bitDepth - 12);
+  const int shiftSampleHor = ::getComponentScaleX(compID, cu.chromaFormat);
+  const int shiftSampleVer = ::getComponentScaleY(compID, cu.chromaFormat);
+  Mv _bv = bv;
+  if( isChroma(compID) )
+  {
+    _bv.hor = (bv.hor >> shiftSampleHor);
+    _bv.ver = (bv.ver >> shiftSampleVer);
+  }
+
+  const Picture&  currPic = *cu.cs->picture;
+  const CodingUnit* const cuAbove = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID));
+  const CodingUnit* const cuLeft = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID));
+  const CPelBuf recBuf = cuAbove || cuLeft ? currPic.getRecoBuf(cu.cs->picture->blocks[compID]) : CPelBuf();
+  const CPelBuf refBuf = cuAbove || cuLeft ? currPic.getRecoBuf(cu.cs->picture->blocks[compID]) : CPelBuf();
+
+  // above
+  const int lumaShift = 2 + MV_FRACTIONAL_BITS_DIFF;
+  if (cuAbove && posH == 0)
+  {
+    Mv mvTop(0, -(1 << shiftSampleVer));
+    mvTop += bv;
+    MotionInfo miTop;
+    miTop.mv[0] = Mv(mvTop.hor << lumaShift, mvTop.ver << lumaShift);
+    miTop.refIdx[0] = MAX_NUM_REF;
+    bool refBvValid = false;
+    if (PU::checkIsIBCCandidateValid(*cu.firstPU, miTop, true, true))
+    {
+      refBvValid = true;
+    }
+    if (refBvValid)
+    {
+      xGetIbcLicPredBlkTpl<true>(cu, compID, refBuf, _bv, posW, posH, sublkWidth, refAboveTemplate);
+      const Pel*    rec = recBuf.bufAt(cu.blocks[compID].pos().offset(0, -1));
+
+      for (int k = posW; k < posW + sublkWidth; k++)
+      {
+        int refVal = refAboveTemplate[k];
+        int recVal = rec[k];
+
+        recVal >>= precShift;
+        refVal >>= precShift;
+
+        refAboveTemplate[k] = refVal;
+        recAboveTemplate[k] = recVal;
+        numTemplate[0]++;
+      }
+    }
+  }
+
+  // left
+  if (cuLeft && posW == 0)
+  {
+    Mv mvLeft(-(1 << shiftSampleHor), 0);
+    mvLeft += bv;
+    MotionInfo miLeft;
+    miLeft.mv[0] = Mv(mvLeft.hor << lumaShift, mvLeft.ver << lumaShift);
+    miLeft.refIdx[0] = MAX_NUM_REF;
+    bool refBvValid = false;
+    if (PU::checkIsIBCCandidateValid(*cu.firstPU, miLeft, true, false))
+    {
+      refBvValid = true;
+    }
+    if (refBvValid)
+    {
+      xGetIbcLicPredBlkTpl<false>(cu, compID, refBuf, _bv, posW, posH, sublkHeight, refLeftTemplate);
+      const Pel*    rec = recBuf.bufAt(cu.blocks[compID].pos().offset(-1, 0));
+
+      for (int k = posH; k < posH + sublkHeight; k++)
+      {
+        int refVal = refLeftTemplate[k];
+        int recVal = rec[recBuf.stride * k];
+
+        recVal >>= precShift;
+        refVal >>= precShift;
+
+        refLeftTemplate[k] = refVal;
+        recLeftTemplate[k] = recVal;
+        numTemplate[1]++;
+      }
+    }
+  }
+}
+
+template <bool trueAfalseL>
+void InterPrediction::xGetIbcLicPredBlkTpl(const CodingUnit& cu, const ComponentID compID, const CPelBuf& refBuf, const Mv& mv, const int posW, const int posH, const int tplSize, Pel* predBlkTpl
+                                     )
+{
+  const int xInt      = mv.getHor();
+  const int yInt      = mv.getVer();
+  const int xFrac     = 0;
+  const int yFrac     = 0;
+
+  const Pel* ref;
+        Pel* dst;
+        int refStride, dstStride, bw, bh;
+  if( trueAfalseL )
+  {
+    ref       = refBuf.bufAt(cu.blocks[compID].pos().offset(xInt + posW, yInt + posH - 1));
+    dst       = predBlkTpl + posW;
+    refStride = refBuf.stride;
+    dstStride = tplSize;
+    bw        = tplSize;
+    bh        = 1;
+  }
+  else
+  {
+    ref       = refBuf.bufAt(cu.blocks[compID].pos().offset(xInt + posW - 1, yInt + posH));
+    dst       = predBlkTpl + posH;
+    refStride = refBuf.stride;
+    dstStride = 1;
+    bw        = 1;
+    bh        = tplSize;
+  }
+
+  const int  nFilterIdx   = 0;
+  const bool useAltHpelIf = false;
+
+  if ( yFrac == 0 )
+  {
+    m_if.filterHor( compID, (Pel*) ref, refStride, dst, dstStride, bw, bh, xFrac, true, cu.chromaFormat, cu.slice->clpRng(compID), nFilterIdx, false, useAltHpelIf);
+  }
+  else if ( xFrac == 0 )
+  {
+    m_if.filterVer( compID, (Pel*) ref, refStride, dst, dstStride, bw, bh, yFrac, true, true, cu.chromaFormat, cu.slice->clpRng(compID), nFilterIdx, false, useAltHpelIf);
+  }
+}
+#endif // IBC_LIC
+
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM
 Distortion InterPrediction::deriveTMMv(const PredictionUnit& pu, bool fillCurTpl, Distortion curBestCost, RefPicList eRefList, int refIdx, int maxSearchRounds, Mv& mv, const MvField* otherMvf)
 {
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 10ef63187eef3d5e18db4adaec81d0d920d61b80..099f5754e618b17b396941086bb717fff85a76cf 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -551,8 +551,12 @@ public:
 #endif
 #if JVET_AA0061_IBC_MBVD || (JVET_W0090_ARMC_TM && JVET_Y0058_IBC_LIST_MODIFY)
   bool xAMLIBCGetCurBlkTemplate(PredictionUnit& pu, int nCurBlkWidth, int nCurBlkHeight);
+#if JVET_AC0112_IBC_LIC
+  void getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth, int nCurBlkHeight, bool doIbcLic = false);
+#else
   void getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth, int nCurBlkHeight);
 #endif
+#endif
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
 #if JVET_Z0054_BLK_REF_PIC_REORDER
   void deriveMVDcand(const PredictionUnit& pu, RefPicList eRefPicList, std::vector<Mv>& cMvdCandList);
@@ -689,6 +693,12 @@ public:
   void    updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, uint32_t* RdCandList, uint32_t startPos,uint32_t endPos);
 #endif
 #endif
+#if JVET_AC0112_IBC_GPM
+  void    motionCompensationIbcGpm(CodingUnit &cu, MergeCtx &ibcGpmMrgCtx, IntraPrediction* pcIntraPred);
+#if JVET_AA0070_RRIBC
+  void    adjustIbcMergeRribcCand(PredictionUnit &pu, MergeCtx& mrgCtx, uint32_t startPos, uint32_t endPos);
+#endif
+#endif
 
 #if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
   template <uint8_t partIdx, bool useDefaultPelBuffer = true>
@@ -727,8 +737,10 @@ public:
     fillPartGPMRefTemplate<partIdx, useDefaultPelBuffer>(pu, bufTop, bufLeft);
   }
 #endif
-#if INTER_LIC
+#if INTER_LIC || JVET_AC0112_IBC_LIC
   void xGetLICParamGeneral (const CodingUnit& cu, const ComponentID compID, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate, Pel* recLeftTemplate, Pel* recAboveTemplate, int& shift, int& scale, int& offset);
+#endif
+#if INTER_LIC
 #if JVET_AA0146_WRAP_AROUND_FIX
   void xGetSublkTemplate   (const CodingUnit& cu, const ComponentID compID, const Picture& refPic, const Mv& mv, const int sublkWidth, const int sublkHeight, const int posW, const int posH, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate, Pel* recLeftTemplate, Pel* recAboveTemplate, bool wrapRef = false);
   void xLocalIlluComp      (const PredictionUnit& pu, const ComponentID compID, const Picture& refPic, const Mv& mv, const bool biPred, PelBuf& dstBuf, bool wrapRef = false);
@@ -745,6 +757,13 @@ public:
                       );
 #endif
 
+#if JVET_AC0112_IBC_LIC
+  void xGetSublkTemplate (const CodingUnit& cu, const ComponentID compID, const Mv& bv, const int sublkWidth, const int sublkHeight, const int posW, const int posH, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate, Pel* recLeftTemplate, Pel* recAboveTemplate);
+  void xLocalIlluComp (const PredictionUnit& pu, const ComponentID compID, const Mv& bv, PelBuf& dstBuf);
+  template <bool trueAfalseL>
+  void xGetIbcLicPredBlkTpl(const CodingUnit& cu, const ComponentID compID, const CPelBuf& refBuf, const Mv& mv, const int posW, const int posH, const int tplSize, Pel* predBlkTpl);
+#endif
+
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index 73492398d58b4d258b13a8dbe125d3e8fc8521c7..3e0eb3ea0cdbf8a2c38f45ed71c06a692516172e 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -336,6 +336,9 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth
 #if JVET_W0123_TIMD_FUSION && INTRA_TRANS_ENC_OPT
   m_timdBlending = timdBlending;
 #endif
+#if JVET_AC0112_IBC_CIIP && INTRA_TRANS_ENC_OPT
+  m_ibcCiipBlending = ibcCiipBlending;
+#endif
 #if JVET_V0130_INTRA_TMP
   unsigned int blkSize;
   if( m_pppTarPatch == NULL )
@@ -966,6 +969,18 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
       int weightMode = ((pu.cu->timd && pu.cu->timdIsBlended) || !applyFusion) ? 4 : 3;
 #else
       int weightMode = ((pu.cu->timd && pu.cu->timdIsBlended) || !applyFusion || (PU::isSgpm(pu, CHANNEL_TYPE_LUMA))) ? 4 : 3;
+#endif
+#if JVET_AC0112_IBC_CIIP
+      if (pu.ibcCiipFlag)
+      {
+        weightMode = 4;
+      }
+#endif
+#if JVET_AC0112_IBC_GPM
+      if (pu.ibcGpmFlag)
+      {
+        weightMode = 4;
+      }
 #endif
       xPredIntraAng(srcBuf, piPred, channelType, clpRng, bExtIntraDir, srcBuf2nd, pu.cu->ispMode != NOT_INTRA_SUBPARTITIONS, weightMode);
         break;
@@ -2729,9 +2744,44 @@ void IntraPrediction::geneWeightedPred( const ComponentID compId, PelBuf& pred,
 #endif
 }
 
+#if JVET_AC0112_IBC_CIIP
+void IntraPrediction::geneWeightedPred( const ComponentID compId, PelBuf& pred, const PredictionUnit &pu, const PelBuf& interPred, const PelBuf& intraPred)
+{
+  const int            width = pred.width;
+  const int            height = pred.height;
+  const Pel*           interPredBuf = interPred.buf;
+  const int            interPredStride = interPred.stride;
+  Pel*                 intraPredBuf = intraPred.buf;
+  const int            intraPredStride = intraPred.stride;
+  const int            dstStride = pred.stride;
+  Pel*                 dstBuf = pred.buf;
+  int wMerge = 13;
+  int wIntra = 3;
+  int shift = 4;
+  if (!pu.mergeFlag)
+  {
+    wMerge = 1;
+    wIntra = 1;
+    shift = 1;
+  }
+  if (width < 4)
+  {
+    ibcCiipBlending(dstBuf, dstStride, interPredBuf, interPredStride, intraPredBuf, intraPredStride, wMerge, wIntra, shift, width, height);
+  }
+  else
+  {
+    m_ibcCiipBlending(dstBuf, dstStride, interPredBuf, interPredStride, intraPredBuf, intraPredStride, wMerge, wIntra, shift, width, height);
+  }
+}
+#endif
+
 void IntraPrediction::geneIntrainterPred(const CodingUnit &cu, PelStorage& pred)
 {
+#if JVET_AC0112_IBC_CIIP
+  if (!cu.firstPU->ciipFlag && !cu.firstPU->ibcCiipFlag)
+#else
   if (!cu.firstPU->ciipFlag)
+#endif
   {
     return;
   }
@@ -2743,6 +2793,17 @@ void IntraPrediction::geneIntrainterPred(const CodingUnit &cu, PelStorage& pred)
   const UnitArea localUnitArea(pu->cs->area.chromaFormat, Area(0, 0, pu->Y().width, pu->Y().height));
   PelBuf ciipBuff = pred.getBuf(localUnitArea.Y());
   predIntraAng(COMPONENT_Y, ciipBuff, *pu);
+#if JVET_AC0112_IBC_CIIP
+#if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
+  const bool chroma = !(CS::isDualITree(*pu->cs));
+#else
+  const bool chroma = !pu.cu->isSepTree();
+#endif
+  if (cu.firstPU->ibcCiipFlag && !chroma)
+  {
+    return;
+  }
+#endif
 
   if (isChromaEnabled(pu->chromaFormat))
   {
@@ -2853,6 +2914,12 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre
   m_ipaParam.fetchRef2nd  &= !(cu.dimd && cu.dimdBlending);
   m_ipaParam.fetchRef2nd  &= !(mrlIndex2D == MULTI_REF_LINE_IDX[MRL_NUM_REF_LINES - 1] && ((cu.block(COMPONENT_Y).y) % ((cu.cs->sps)->getMaxCUWidth()) <= MULTI_REF_LINE_IDX[MRL_NUM_REF_LINES - 1]));
   m_ipaParam.fetchRef2nd  &= !(mrlIndex2D == 0 && ((cu.block(COMPONENT_Y).y) % ((cu.cs->sps)->getMaxCUWidth()) == 0));
+#if JVET_AC0112_IBC_CIIP
+  m_ipaParam.fetchRef2nd &= !cu.firstPU->ibcCiipFlag;
+#endif
+#if JVET_AC0112_IBC_GPM
+  m_ipaParam.fetchRef2nd &= !cu.firstPU->ibcGpmFlag;
+#endif
 #endif
 
   if (!forceRefFilterFlag)
@@ -5521,6 +5588,28 @@ void IntraPrediction::timdBlending(Pel *pDst, int strideDst, Pel *pSrc, int stri
 #endif
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+void IntraPrediction::ibcCiipBlending(Pel *pDst, int strideDst, const Pel *pSrc0, int strideSrc0, Pel *pSrc1, int strideSrc1, int w0, int w1, int shift, int width, int height)
+{
+  Pel *pelPred = pDst;
+  const Pel *pelPlanar = pSrc0;
+  Pel *pelPredAng = pSrc1;
+  int offset = 1 << (shift - 1);
+  for (int y = 0; y < height; y++)
+  {
+    for (int x = 0; x < width; x++)
+    {
+      int blend = pelPlanar[x] * w0;
+      blend += pelPredAng[x] * w1;
+      pelPred[x] = (Pel)((blend + offset) >> shift);
+    }
+    pelPred += strideDst;
+    pelPlanar += strideSrc0;
+    pelPredAng += strideSrc1;
+  }
+}
+#endif
+
 #if ENABLE_DIMD
 void IntraPrediction::deriveDimdMode(const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu)
 {
@@ -10404,7 +10493,11 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR
     }
   }
   // left (Inter)
+#if JVET_AC0112_IBC_CIIP
+  if (puLeft && (CU::isInter(*puLeft->cu) || CU::isIBC(*puLeft->cu)))
+#else
   if (puLeft && CU::isInter(*puLeft->cu))
+#endif
   {
     tmrlIntraList[sizeMode] = puLeft->getIpmInfo(posL);
     if (!includedMode[tmrlIntraList[sizeMode]])
@@ -10413,7 +10506,11 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR
     }
   }
   // above (Inter)
+#if JVET_AC0112_IBC_CIIP
+  if (puAbove && (CU::isInter(*puAbove->cu) || CU::isIBC(*puAbove->cu)))
+#else
   if (puAbove && CU::isInter(*puAbove->cu))
+#endif
   {
     tmrlIntraList[sizeMode] = puAbove->getIpmInfo(posA);
     if (!includedMode[tmrlIntraList[sizeMode]])
@@ -10467,7 +10564,11 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR
   }
 
   // above left (Inter)
+#if JVET_AC0112_IBC_CIIP
+  if (puAboveLeft && (CU::isInter(*puAboveLeft->cu) || CU::isIBC(*puAboveLeft->cu)))
+#else
   if (puAboveLeft && CU::isInter(*puAboveLeft->cu))
+#endif
   {
     tmrlIntraList[sizeMode] = puAboveLeft->getIpmInfo(posAL);
     if (!includedMode[tmrlIntraList[sizeMode]])
@@ -10477,7 +10578,11 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR
   }
 
   // left bottom (Inter)
+#if JVET_AC0112_IBC_CIIP
+  if (puLeftBottom && (CU::isInter(*puLeftBottom->cu) || CU::isIBC(*puLeftBottom->cu)))
+#else
   if (puLeftBottom && CU::isInter(*puLeftBottom->cu))
+#endif
   {
     tmrlIntraList[sizeMode] = puLeftBottom->getIpmInfo(posLB);
     if (!includedMode[tmrlIntraList[sizeMode]])
@@ -10487,7 +10592,11 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR
   }
 
   // above right (Inter)
+#if JVET_AC0112_IBC_CIIP
+  if (puAboveRight && (CU::isInter(*puAboveRight->cu) || CU::isIBC(*puAboveRight->cu)))
+#else
   if (puAboveRight && CU::isInter(*puAboveRight->cu))
+#endif
   {
     tmrlIntraList[sizeMode] = puAboveRight->getIpmInfo(posAR);
     if (!includedMode[tmrlIntraList[sizeMode]])
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index 96c332be4621d9d50b007c54654a2d198fbd308b..dcbef1761b998c504894beaadc4f252bbbb05312 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -317,10 +317,12 @@ protected:
 #else
   void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const ClpRng& clpRng);
 #endif
+#if !(JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM)
 #if JVET_AB0155_SGPM
   void initPredIntraParams(const PredictionUnit &pu, const CompArea compArea, const SPS &sps, const int partIdx = 0);
 #else
   void initPredIntraParams        ( const PredictionUnit & pu,  const CompArea compArea, const SPS& sps );
+#endif
 #endif
 
   static bool isIntegerSlope(const int absAng) { return (0 == (absAng & 0x1F)); }
@@ -510,6 +512,13 @@ public:
 #endif
   /// set parameters from CU data for accessing intra data
   
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+#if JVET_AB0155_SGPM
+  void initPredIntraParams(const PredictionUnit &pu, const CompArea compArea, const SPS &sps, const int partIdx = 0);
+#else
+  void initPredIntraParams        ( const PredictionUnit & pu,  const CompArea compArea, const SPS& sps );
+#endif
+#endif
 #if JVET_AB0155_SGPM
   void initIntraPatternChType(const CodingUnit &cu, const CompArea &area, const bool forceRefFilterFlag = false,
     const int partIdx = 0
@@ -539,6 +548,11 @@ public:
   void geneIntrainterPred         (const CodingUnit &cu, PelStorage& pred);
 #if JVET_Z0050_DIMD_CHROMA_FUSION
   void geneChromaFusionPred       (const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu);
+#endif
+#if JVET_AC0112_IBC_CIIP
+  void geneWeightedPred           ( const ComponentID compId, PelBuf& pred, const PredictionUnit &pu, const PelBuf& interPred, const PelBuf& intraPred);
+  void(*m_ibcCiipBlending)           ( Pel *pDst, int strideDst, const Pel *pSrc0, int strideSrc0, Pel *pSrc1, int strideSrc1, int w0, int w1, int shift, int width, int height );
+  static void ibcCiipBlending        ( Pel *pDst, int strideDst, const Pel *pSrc0, int strideSrc0, Pel *pSrc1, int strideSrc1, int w0, int w1, int shift, int width, int height );
 #endif
   void reorderPLT                 (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp);
 #if !MERGE_ENC_OPT
diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h
index ab4595ae0de29bc8c4ea714c03f2cc856c055753..4fe3a2cc334ca2d394f71f8bbfbc91a06462889b 100644
--- a/source/Lib/CommonLib/MotionInfo.h
+++ b/source/Lib/CommonLib/MotionInfo.h
@@ -176,6 +176,9 @@ struct MotionInfo
 #if INTER_LIC
   bool     usesLIC;
 #endif
+#if JVET_AC0112_IBC_LIC
+  bool     useIbcLic;
+#endif
 #if JVET_AA0070_RRIBC
   int  rribcFlipType;
   Position centerPos;
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index e48999df884d0478bf08ff2beb7a3c644658f693..19805abed8c3d5f12be97f7818de395cd1c51628 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -5437,4 +5437,27 @@ const int8_t g_glmPattern[NUM_GLM_PATTERN][6] =
 #endif
 };
 #endif
+#if JVET_AC0112_IBC_GPM
+const int8_t g_ibcGpmFirstSetSplitDirToIdx[GEO_NUM_PARTITION_MODE] = {
+0,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,2,3,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,4,5,0,0,
+0,0,0,0,0,0,0,0,
+0,0,6,7,0,0,0,0,
+0,0,0,0,0,0,0,0
+};
+const int8_t g_ibcGpmFirstSetSplitDir[IBC_GPM_MAX_SPLIT_DIR_FIRST_SET_NUM] = {0, 1, 18, 19, 36, 37, 50, 51};
+const int8_t g_ibcGpmSecondSetSplitDir[GEO_NUM_PARTITION_MODE] = {
+0,0,1,1,0,1,1,1,
+0,1,1,1,0,1,1,1,
+0,1,0,0,1,1,0,1,
+1,1,0,1,1,1,0,1,
+1,1,0,1,0,0,1,0,
+1,1,0,1,1,0,1,1,
+0,1,0,0,1,0,1,1,
+0,1,1,0,1,1,0,1
+};
+#endif
 //! \}
diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h
index ad83eea26461b138a12b4b2fd2db7b86ee4180ed..d6d0bf97cdb75e7f5c852da950bba55bbbb15106 100644
--- a/source/Lib/CommonLib/Rom.h
+++ b/source/Lib/CommonLib/Rom.h
@@ -398,5 +398,10 @@ extern int g_rmvfMultApproxTbl[3 << sizeof(int64_t)];
 #if JVET_AA0126_GLM
 extern const int8_t g_glmPattern[NUM_GLM_PATTERN][6];
 #endif
+#if JVET_AC0112_IBC_GPM
+extern const int8_t g_ibcGpmFirstSetSplitDirToIdx[GEO_NUM_PARTITION_MODE];
+extern const int8_t g_ibcGpmFirstSetSplitDir[IBC_GPM_MAX_SPLIT_DIR_FIRST_SET_NUM];
+extern const int8_t g_ibcGpmSecondSetSplitDir[GEO_NUM_PARTITION_MODE];
+#endif
 #endif  //__TCOMROM__
 
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 4c61ba0096d8e72b381252e9f29ef9225ebe53d2..e2eab4150831654411a6a161f7e5e7c24869355e 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -3590,6 +3590,15 @@ SPS::SPS()
 #if JVET_AA0061_IBC_MBVD
   , m_ibcMbvd                 ( false )
 #endif
+#if JVET_AC0112_IBC_CIIP
+  , m_ibcCiip                 ( false )
+#endif
+#if JVET_AC0112_IBC_GPM
+  , m_ibcGpm                  ( false )
+#endif
+#if JVET_AC0112_IBC_LIC
+  , m_ibcLic                  ( false )
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
  , m_DMVDMode                 ( false )
 #endif
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 27de480ca42497a2e08eaf0be98209e4fe34f239..3173e436cce291f44abb8b384569e23cca223e2e 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1530,6 +1530,15 @@ private:
 #if JVET_AA0061_IBC_MBVD
   bool              m_ibcMbvd;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  bool              m_ibcCiip;
+#endif
+#if JVET_AC0112_IBC_GPM
+  bool              m_ibcGpm;
+#endif
+#if JVET_AC0112_IBC_LIC
+  bool              m_ibcLic;
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   bool              m_DMVDMode;
 #endif
@@ -2056,6 +2065,18 @@ void                    setCCALFEnabledFlag( bool b )
   void                    setUseIbcMbvd(bool b)                                                           { m_ibcMbvd = b; }
   bool                    getUseIbcMbvd() const                                                           { return m_ibcMbvd; }
 #endif
+#if JVET_AC0112_IBC_CIIP
+  void                    setUseIbcCiip(bool b)                                                           { m_ibcCiip = b; }
+  bool                    getUseIbcCiip() const                                                           { return m_ibcCiip; }
+#endif
+#if JVET_AC0112_IBC_GPM
+  void                    setUseIbcGpm(bool b)                                                            { m_ibcGpm = b; }
+  bool                    getUseIbcGpm() const                                                            { return m_ibcGpm; }
+#endif
+#if JVET_AC0112_IBC_LIC
+  void                    setUseIbcLic(bool b)                                                            { m_ibcLic = b; }
+  bool                    getUseIbcLic() const                                                            { return m_ibcLic; }
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   void                    setUseDMVDMode(bool b)                                                          { m_DMVDMode = b; }
   bool                    getUseDMVDMode() const                                                          { return m_DMVDMode; }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index bbfec32d3485547f865d34b4625d4a55d749d318..49147eb747e9e9e918fdaaa58a146334f90afa95 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -175,6 +175,9 @@
 #define JVET_AA0106_IBCBUF_CTU256                         1 // JVET-AA0106: Adjust IBC reference area to 2*128 rows above the current CTU
 #define JVET_AA0061_IBC_MBVD                              1 // JVET-AA0061: IBC merge mode with block vector differences
 #define JVET_AA0070_RRIBC                                 1 // JVET-AA0070: Reconstruction-Reordered IBC
+#define JVET_AC0112_IBC_CIIP                              1 // JVET-AC0112: Combined IBC and intra prediction (IBC-CIIP)
+#define JVET_AC0112_IBC_GPM                               1 // JVET-AC0112: IBC with geometry partitioning mode (IBC-GPM)
+#define JVET_AC0112_IBC_LIC                               1 // JVET-AC0112: IBC with local illumination compensation (IBC-LIC)
 
 // Inter
 #define CIIP_PDPC                                         1 // Apply pdpc to megre prediction as a new CIIP mode (CIIP_PDPC) additional to CIIP mode
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 3f2d00b06d4ffe1126cfbfe6ea490e3070d19b40..91f75776c71193fd8b9f6419ddf7d6360ecfa5a0 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -352,6 +352,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
 #if INTER_LIC
   LICFlag           = other.LICFlag;
 #endif
+#if JVET_AC0112_IBC_LIC
+  ibcLicFlag = other.ibcLicFlag;
+#endif
 #if JVET_AA0070_RRIBC
   rribcFlipType = other.rribcFlipType;
 #endif
@@ -490,6 +493,9 @@ void CodingUnit::initData()
 #if INTER_LIC
   LICFlag = false;
 #endif
+#if JVET_AC0112_IBC_LIC
+  ibcLicFlag = false;
+#endif
 #if JVET_AA0070_RRIBC
   rribcFlipType = 0;
 #endif
@@ -801,6 +807,13 @@ void PredictionUnit::initData()
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   reduceTplSize = false;
 #endif
+#if JVET_AC0112_IBC_GPM
+  ibcGpmFlag = false;
+  ibcGpmSplitDir = MAX_UCHAR;
+  ibcGpmMergeIdx0 = MAX_UCHAR;
+  ibcGpmMergeIdx1 = MAX_UCHAR;
+  ibcGpmBldIdx = MAX_UCHAR;
+#endif
 
 #if JVET_Z0054_BLK_REF_PIC_REORDER
   refIdxLC = -1;
@@ -831,6 +844,10 @@ void PredictionUnit::initData()
   ciipFlag = false;
 #if CIIP_PDPC
   ciipPDPC = false;
+#endif
+#if JVET_AC0112_IBC_CIIP
+  ibcCiipFlag = false;
+  ibcCiipIntraIdx = 0;
 #endif
   mmvdEncOptMode = 0;
 #if MULTI_HYP_PRED
@@ -939,6 +956,13 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData)
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   reduceTplSize = predData.reduceTplSize;
 #endif
+#if JVET_AC0112_IBC_GPM
+  ibcGpmFlag = predData.ibcGpmFlag;
+  ibcGpmSplitDir = predData.ibcGpmSplitDir;
+  ibcGpmMergeIdx0 = predData.ibcGpmMergeIdx0;
+  ibcGpmMergeIdx1 = predData.ibcGpmMergeIdx1;
+  ibcGpmBldIdx = predData.ibcGpmBldIdx;
+#endif
 
   for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++)
   {
@@ -970,6 +994,10 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData)
 #if CIIP_PDPC
   ciipPDPC = predData.ciipPDPC;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  ibcCiipFlag = predData.ibcCiipFlag;
+  ibcCiipIntraIdx = predData.ibcCiipIntraIdx;
+#endif
 #if MULTI_HYP_PRED
   addHypData = predData.addHypData;
   numMergedAddHyps = predData.numMergedAddHyps;
@@ -1073,6 +1101,13 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   reduceTplSize = other.reduceTplSize;
 #endif
+#if JVET_AC0112_IBC_GPM
+  ibcGpmFlag = other.ibcGpmFlag;
+  ibcGpmSplitDir = other.ibcGpmSplitDir;
+  ibcGpmMergeIdx0 = other.ibcGpmMergeIdx0;
+  ibcGpmMergeIdx1 = other.ibcGpmMergeIdx1;
+  ibcGpmBldIdx = other.ibcGpmBldIdx;
+#endif
 
   for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++)
   {
@@ -1104,6 +1139,10 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
 #if CIIP_PDPC
   ciipPDPC = other.ciipPDPC;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  ibcCiipFlag = other.ibcCiipFlag;
+  ibcCiipIntraIdx = other.ibcCiipIntraIdx;
+#endif
 #if MULTI_HYP_PRED
   addHypData = other.addHypData;
   numMergedAddHyps = other.numMergedAddHyps;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index f953b73293c673f4ee84c1613fe1ef635036dfb1..18be8cd365eb7c4802bb6e85d465fa8801e2d1a6 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -386,6 +386,9 @@ struct CodingUnit : public UnitArea
 #if INTER_LIC
   bool           LICFlag;
 #endif
+#if JVET_AC0112_IBC_LIC
+  bool ibcLicFlag;
+#endif
 #if JVET_AA0070_RRIBC
   int    rribcFlipType;
 #endif
@@ -526,6 +529,17 @@ struct InterPredictionData
   bool          ibcMbvdMergeFlag;
   int           ibcMbvdMergeIdx;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  bool        ibcCiipFlag;
+  int         ibcCiipIntraIdx;
+#endif
+#if JVET_AC0112_IBC_GPM
+  bool        ibcGpmFlag;
+  uint8_t     ibcGpmSplitDir;
+  uint8_t     ibcGpmMergeIdx0;
+  uint8_t     ibcGpmMergeIdx1;
+  uint8_t     ibcGpmBldIdx;
+#endif
 #if AFFINE_MMVD
   bool        afMmvdFlag;
   uint8_t     afMmvdBaseIdx; // base vector's merge index at the affine merge list, excluding sbTmvp
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 3dede761adb5658efb8e19097529aa8ab3f96b79..757acf84656932d78dbf6b131478f6d192152b6e 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -877,7 +877,11 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType
 
 #if SECONDARY_MPM
 #if JVET_W0123_TIMD_FUSION
+#if JVET_AC0112_IBC_CIIP
+    if (puLeft && (CU::isInter(*puLeft->cu) || CU::isIBC(*puLeft->cu)))
+#else
     if (puLeft && CU::isInter(*puLeft->cu))
+#endif
     {
       mpm[numValidMPM] = puLeft->getIpmInfo(pu.lheight() >= pu.lwidth() ? posRT.offset(0, -1) : posLB.offset(-1, 0));
       if( !includedMode[mpm[numValidMPM]] )
@@ -885,7 +889,11 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType
         includedMode[mpm[numValidMPM++]] = true;
       }
     }
+#if JVET_AC0112_IBC_CIIP
+    if (puAbove && (CU::isInter(*puAbove->cu) || CU::isIBC(*puAbove->cu)))
+#else
     if (puAbove && CU::isInter(*puAbove->cu))
+#endif
     {
       mpm[numValidMPM] = puAbove->getIpmInfo(pu.lheight() >= pu.lwidth() ? posLB.offset(-1, 0) : posRT.offset(0, -1));
       if( !includedMode[mpm[numValidMPM]] )
@@ -940,7 +948,11 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType
       }
     }
 #if JVET_W0123_TIMD_FUSION
+#if JVET_AC0112_IBC_CIIP
+    if (puBelowLeft && (CU::isInter(*puBelowLeft->cu) || CU::isIBC(*puBelowLeft->cu)))
+#else
     if (puBelowLeft && CU::isInter(*puBelowLeft->cu))
+#endif
     {
       mpm[numValidMPM] = puBelowLeft->getIpmInfo(posLB.offset(-1, 1));
       if( !includedMode[mpm[numValidMPM]] )
@@ -948,7 +960,11 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType
         includedMode[mpm[numValidMPM++]] = true;
       }
     }
+#if JVET_AC0112_IBC_CIIP
+    if (puAboveRight && (CU::isInter(*puAboveRight->cu) || CU::isIBC(*puAboveRight->cu)))
+#else
     if (puAboveRight && CU::isInter(*puAboveRight->cu))
+#endif
     {
       mpm[numValidMPM] = puAboveRight->getIpmInfo(posRT.offset(1, -1));
       if( !includedMode[mpm[numValidMPM]] )
@@ -956,7 +972,11 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType
         includedMode[mpm[numValidMPM++]] = true;
       }
     }
+#if JVET_AC0112_IBC_CIIP
+    if (puAboveLeft && (CU::isInter(*puAboveLeft->cu) || CU::isIBC(*puAboveLeft->cu)))
+#else
     if (puAboveLeft && CU::isInter(*puAboveLeft->cu))
+#endif
     {
       mpm[numValidMPM] = puAboveLeft->getIpmInfo(posTL.offset(-1, -1));
       if( !includedMode[mpm[numValidMPM]] )
@@ -1636,7 +1656,11 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD
   if (shape == GEO_TM_SHAPE_L || shape == GEO_TM_SHAPE_AL)
   {
     const PredictionUnit *puLeft = pu.cs->getPURestricted(posL, pu, CHANNEL_TYPE_LUMA);
+#if JVET_AC0112_IBC_CIIP
+    if (puLeft && (CU::isInter(*puLeft->cu) || CU::isIBC(*puLeft->cu)))
+#else
     if (puLeft && CU::isInter(*puLeft->cu))
+#endif
     {
       mpm[numValidMPM] = puLeft->getIpmInfo(posL);
       if (!includedMode[mpm[numValidMPM]])
@@ -1653,7 +1677,11 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD
   if (shape == GEO_TM_SHAPE_A || shape == GEO_TM_SHAPE_AL)
   {
     const PredictionUnit *puAbove = pu.cs->getPURestricted(posA, pu, CHANNEL_TYPE_LUMA);
+#if JVET_AC0112_IBC_CIIP
+    if (puAbove && (CU::isInter(*puAbove->cu) || CU::isIBC(*puAbove->cu)))
+#else
     if (puAbove && CU::isInter(*puAbove->cu))
+#endif
     {
       mpm[numValidMPM] = puAbove->getIpmInfo(posA);
       if (!includedMode[mpm[numValidMPM]])
@@ -1737,7 +1765,11 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD
   if (shape == GEO_TM_SHAPE_L || shape == GEO_TM_SHAPE_AL)
   {
     const PredictionUnit *puBelowLeft = pu.cs->getPURestricted(posBL, pu, CHANNEL_TYPE_LUMA);
+#if JVET_AC0112_IBC_CIIP
+    if (puBelowLeft && (CU::isInter(*puBelowLeft->cu) || CU::isIBC(*puBelowLeft->cu)))
+#else
     if (puBelowLeft && CU::isInter(*puBelowLeft->cu))
+#endif
     {
       mpm[numValidMPM] = puBelowLeft->getIpmInfo(posBL);
       if (!includedMode[mpm[numValidMPM]])
@@ -1754,7 +1786,11 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD
   if (shape == GEO_TM_SHAPE_A || shape == GEO_TM_SHAPE_AL)
   {
     const PredictionUnit *puAboveRight = pu.cs->getPURestricted(posAR, pu, CHANNEL_TYPE_LUMA);
+#if JVET_AC0112_IBC_CIIP
+    if (puAboveRight && (CU::isInter(*puAboveRight->cu) || CU::isIBC(*puAboveRight->cu)))
+#else
     if (puAboveRight && CU::isInter(*puAboveRight->cu))
+#endif
     {
       mpm[numValidMPM] = puAboveRight->getIpmInfo(posAR);
       if (!includedMode[mpm[numValidMPM]])
@@ -1770,7 +1806,11 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD
 
   {
     const PredictionUnit *puAboveLeft = pu.cs->getPURestricted(posAL, pu, CHANNEL_TYPE_LUMA);
+#if JVET_AC0112_IBC_CIIP
+    if (puAboveLeft && (CU::isInter(*puAboveLeft->cu) || CU::isIBC(*puAboveLeft->cu)))
+#else
     if (puAboveLeft && CU::isInter(*puAboveLeft->cu))
+#endif
     {
       mpm[numValidMPM] = puAboveLeft->getIpmInfo(posAL);
       if (!includedMode[mpm[numValidMPM]])
@@ -2407,6 +2447,13 @@ bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int
         CHECK(mrgCtx.LICFlags[cnt], "addMergeHMVPCand: LIC is not used with IBC mode")
       }
 #endif
+#endif
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+      mrgCtx.ibcLicFlags       [cnt] = mrgCtx.rribcFlipTypes[cnt] ? false : miNeighbor.useIbcLic;
+#else
+      mrgCtx.ibcLicFlags       [cnt] = miNeighbor.useIbcLic;
+#endif
 #endif
 
       mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
@@ -2684,6 +2731,9 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 #if INTER_LIC
     mrgCtx.LICFlags[ui] = false;
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[ui] =false;
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtx.rribcFlipTypes[ui] = 0;
 #endif
@@ -2744,6 +2794,13 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
     mrgCtx.rribcFlipTypes[cnt] = miLeft.isIBCmot ? miLeft.rribcFlipType : 0;
 #endif
 #endif
+#endif
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+    mrgCtx.ibcLicFlags[cnt] = miLeft.isIBCmot && mrgCtx.rribcFlipTypes[cnt] == 0 ? miLeft.useIbcLic : false;
+#else
+    mrgCtx.ibcLicFlags[cnt] = miLeft.isIBCmot? miLeft.useIbcLic : false;
+#endif
 #endif
     if (mrgCandIdx == cnt)
     {
@@ -2801,6 +2858,13 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 #endif
 #endif
 #endif
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+      mrgCtx.ibcLicFlags[cnt] = miAbove.isIBCmot && mrgCtx.rribcFlipTypes[cnt] == 0 ? miAbove.useIbcLic : false;
+#else
+      mrgCtx.ibcLicFlags[cnt] = miAbove.isIBCmot ? miAbove.useIbcLic : false;
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
       if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2863,6 +2927,13 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 #endif
 #endif
 #endif
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+        mrgCtx.ibcLicFlags[cnt] = miAboveRight.isIBCmot && mrgCtx.rribcFlipTypes[cnt] == 0 ? miAboveRight.useIbcLic : false;
+#else
+        mrgCtx.ibcLicFlags[cnt] = miAboveRight.isIBCmot? miAboveRight.useIbcLic : false;
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
         if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2921,6 +2992,13 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 #endif
 #endif
 #endif
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+        mrgCtx.ibcLicFlags[cnt] = miBelowLeft.isIBCmot && mrgCtx.rribcFlipTypes[cnt] == 0 ? miBelowLeft.useIbcLic : false;
+#else
+        mrgCtx.ibcLicFlags[cnt] = miBelowLeft.isIBCmot ? miBelowLeft.useIbcLic : false;
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
         if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2989,6 +3067,13 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 #endif
 #endif
 #endif
+#if JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+          mrgCtx.ibcLicFlags[cnt] = miAboveLeft.isIBCmot && mrgCtx.rribcFlipTypes[cnt] == 0 ? miAboveLeft.useIbcLic : false;
+#else
+          mrgCtx.ibcLicFlags[cnt] = miAboveLeft.isIBCmot ? miAboveLeft.useIbcLic : false;
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
           if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -3183,6 +3268,9 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
     miCand.mv[0] = mvp;
     mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(mvp, MAX_NUM_REF);
     mrgCtx.interDirNeighbours[cnt] = 1;
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[cnt] = false;
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtx.rribcFlipTypes[cnt] = 0;
 #endif
@@ -3207,6 +3295,9 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   {
     mrgCtx.interDirNeighbours[cnt] = 1;
     mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), MAX_NUM_REF);
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[cnt] = false;
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtx.rribcFlipTypes[cnt] = 0;
 #endif
@@ -3627,6 +3718,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #if INTER_LIC
     mrgCtx.LICFlags[ui] = false;
 #endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[ui] = false;
+#endif
 #if JVET_AA0070_RRIBC
     mrgCtx.rribcFlipTypes[ui] = 0;
 #endif
@@ -12673,6 +12767,9 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
 #if INTER_LIC
     mi.usesLIC = pu.cu->LICFlag;
 #endif
+#if JVET_AC0112_IBC_LIC
+    mi.useIbcLic = mi.isIBCmot ? pu.cu->ibcLicFlag : 0;
+#endif
 #if JVET_AA0070_RRIBC
     mi.rribcFlipType = mi.isIBCmot ? pu.cu->rribcFlipType : 0;
 #endif
@@ -12760,6 +12857,13 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
 #endif
         )
       {
+#if JVET_AC0112_IBC_CIIP
+        if (mi.isIBCmot)
+        {
+          spanIpmInfoIBC(pu, ib, mi.bv.getHor(), mi.bv.getVer());
+        }
+        else
+#endif
         ib.fill(PLANAR_IDX);
       }
       else
@@ -14314,6 +14418,36 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
   spanIpmInfoInter( pu, mb, ib );
 #endif
 }
+
+#if JVET_AC0112_IBC_CIIP
+void PU::spanIpmInfoIBC( PredictionUnit &pu, IpmBuf &ib, int bvx, int bvy )
+{
+  uint8_t* ii = ib.buf;
+  int ibH = ib.height;
+  int ibW = ib.width;
+  const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);
+  const unsigned mask = ~(scale - 1);
+  Position PosY;
+  PosY.x = pu.Y().x + bvx;
+  PosY.y = pu.Y().y + bvy;
+  PosY.x = (PosY.x & mask);
+  PosY.y = (PosY.y & mask);
+  CodingStructure *cs = pu.cs;
+  while (cs != NULL && !cs->area.Y().contains(PosY))
+  {
+    cs = cs->parent;
+  }
+  const uint8_t ipm = cs->getIpmInfo(PosY);
+  for (int y = 0; y < ibH; y++)
+  {
+    for (int x = 0; x < ibW; x++)
+    {
+      ii[x] = ipm;
+    }
+    ii += ib.stride;
+  }
+}
+#endif
 #endif
 
 #if JVET_Z0054_BLK_REF_PIC_REORDER
@@ -15698,4 +15832,4 @@ bool CU::isDirectionalPlanarAvailable(const CodingUnit &cu)
   
   return false;
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 69be809784e319d7d92d8786ea6521fcee990b92..90182f6fde82a2af4c428dd3d1450ed73d28b852 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -364,6 +364,9 @@ namespace PU
 #endif
   void spanIpmInfoIntra               (      PredictionUnit &pu );
   void spanIpmInfoInter               (      PredictionUnit &pu, MotionBuf &mb, IpmBuf &ib );
+#if JVET_AC0112_IBC_CIIP
+  void spanIpmInfoIBC                 (      PredictionUnit &pu, IpmBuf &ib, int bvx, int bvy );
+#endif
 #endif
 #if JVET_AB0155_SGPM
   void spanIpmInfoSgpm                (      PredictionUnit &pu);
@@ -798,6 +801,77 @@ uint32_t updateGeoMMVDCandList(double uiCost, int splitDir, int mergeCand0, int
   return 0;
 }
 
+#if JVET_AC0112_IBC_GPM
+template<size_t N>
+uint32_t updateGeoIbcCandList(double uiCost, int splitDir, int mergeCand0, int mergeCand1, int mmvdCand0, int mmvdCand1,
+  static_vector<double, N>& candCostList, static_vector<int, N>& geoSplitDirList, static_vector<int, N>& geoMergeCand0, static_vector<int, N>& geoMergeCand1, size_t uiFastCandNum)
+{
+  size_t i;
+  size_t shift = 0;
+  size_t currSize = std::min(uiFastCandNum, candCostList.size());
+
+  while (shift < uiFastCandNum && shift < currSize && uiCost < candCostList[currSize - 1 - shift])
+  {
+    shift++;
+  }
+
+  if (candCostList.size() >= uiFastCandNum && shift != 0)
+  {
+    for (i = 1; i < shift; i++)
+    {
+      geoSplitDirList[currSize - i] = geoSplitDirList[currSize - 1 - i];
+      geoMergeCand0[currSize - i] = geoMergeCand0[currSize - 1 - i];
+      geoMergeCand1[currSize - i] = geoMergeCand1[currSize - 1 - i];
+      candCostList[currSize - i] = candCostList[currSize - 1 - i];
+    }
+    geoSplitDirList[currSize - shift] = splitDir;
+    geoMergeCand0[currSize - shift] = mergeCand0;
+    geoMergeCand1[currSize - shift] = mergeCand1;
+    candCostList[currSize - shift] = uiCost;
+    return 1;
+  }
+  else if (currSize < uiFastCandNum)
+  {
+    geoSplitDirList.insert(geoSplitDirList.end() - shift, splitDir);
+    geoMergeCand0.insert(geoMergeCand0.end() - shift, mergeCand0);
+    geoMergeCand1.insert(geoMergeCand1.end() - shift, mergeCand1);
+    candCostList.insert(candCostList.end() - shift, uiCost);
+    return 1;
+  }
+  return 0;
+}
+
+template<size_t N>
+void sortCandList(double uiCost, int mergeCand, static_vector<double, N>& candCostList, static_vector<int, N>& mergeCandList, int fastCandNum)
+{
+  size_t i;
+  size_t shift = 0;
+  size_t currSize = candCostList.size();
+  CHECK(currSize > fastCandNum, "list overflow!");
+
+  while (shift < currSize && uiCost < candCostList[currSize - 1 - shift])
+  {
+    shift++;
+  }
+
+  if (currSize == fastCandNum && shift != 0)
+  {
+    for (i = 1; i < shift; i++)
+    {
+      mergeCandList[currSize - i] = mergeCandList[currSize - 1 - i];
+      candCostList[currSize - i] = candCostList[currSize - 1 - i];
+    }
+    mergeCandList[currSize - shift] = mergeCand;
+    candCostList[currSize - shift] = uiCost;
+  }
+  else if (currSize < fastCandNum)
+  {
+    mergeCandList.insert(mergeCandList.end() - shift, mergeCand);
+    candCostList.insert(candCostList.end() - shift, uiCost);
+  }
+}
+#endif
+
 template<size_t N>
 void sortCandList(double uiCost, int mergeCand, int mmvdCand, static_vector<double, N>& candCostList, static_vector<int, N>& mergeCandList, static_vector<int, N>& mmvdCandList, int fastCandNum)
 {
diff --git a/source/Lib/CommonLib/x86/IntraX86.h b/source/Lib/CommonLib/x86/IntraX86.h
index faba4e217ceffe34c12dcc0d901b02246e6f2f79..a8950ba493e7c89fa8e8ce66b4518c4e73465f09 100644
--- a/source/Lib/CommonLib/x86/IntraX86.h
+++ b/source/Lib/CommonLib/x86/IntraX86.h
@@ -369,6 +369,74 @@ void timdBlendingSIMD( Pel *pDst, int strideDst, Pel *pSrc, int strideSrc, int w
 }
 #endif
 
+#if JVET_AC0112_IBC_CIIP && INTRA_TRANS_ENC_OPT
+template< X86_VEXT vext >
+void ibcCiipBlendingSIMD( Pel *pDst, int strideDst, const Pel *pSrc0, int strideSrc0, Pel *pSrc1, int strideSrc1, int w0, int w1, int shift, int width, int height )
+{
+#if USE_AVX2
+  if ((vext >= AVX2) && (width & 0x7) == 0)
+  {
+    const int offset = 1 << (shift - 1);
+    __m256i mw = _mm256_unpacklo_epi16(_mm256_set1_epi16(w0), _mm256_set1_epi16(w1));
+    __m256i voffset = _mm256_set1_epi32(offset);
+    __m256i msrc0, msrc1, msum0, msum1;
+
+    for (int row = 0; row < height; row++)
+    {
+      for (int col = 0; col < width; col += 8)
+      {
+        msrc0 = _mm256_castsi128_si256(_mm_lddqu_si128((__m128i*)(&pSrc0[col])));
+        msrc1 = _mm256_castsi128_si256(_mm_lddqu_si128((__m128i*)(&pSrc1[col])));
+        msum0 = _mm256_unpacklo_epi16(msrc0, msrc1);
+        msum1 = _mm256_unpackhi_epi16(msrc0, msrc1);
+        msum0 = _mm256_madd_epi16(msum0, mw);
+        msum1 = _mm256_madd_epi16(msum1, mw);
+        msum0 = _mm256_add_epi32(msum0, voffset);
+        msum1 = _mm256_add_epi32(msum1, voffset);
+        msum0 = _mm256_srai_epi32(msum0, shift);
+        msum1 = _mm256_srai_epi32(msum1, shift);
+        msum0 = _mm256_packs_epi32(msum0, msum1);
+        _mm_storeu_si128((__m128i *)&pDst[col], _mm256_castsi256_si128(msum0));
+      }
+      pSrc0 += strideSrc0;
+      pSrc1 += strideSrc1;
+      pDst += strideDst;
+    }
+  }
+  else
+  {
+#endif
+    __m128i vw0 = _mm_set1_epi32( w0 );
+    __m128i vw1 = _mm_set1_epi32( w1 );
+    const int offset = 1 << (shift - 1);
+    __m128i voffset  = _mm_set1_epi32( offset );
+
+    for( int i = 0; i < height; i++ )
+    {
+      for( int j = 0; j < width; j += 4 )
+      {
+        __m128i vdst = _mm_cvtepi16_epi32( _mm_loadl_epi64( (__m128i*)(pDst + j) ) );
+        __m128i vsrc0 = _mm_cvtepi16_epi32( _mm_loadl_epi64( (__m128i*)(pSrc0 + j) ) );
+        __m128i vsrc1 = _mm_cvtepi16_epi32( _mm_loadl_epi64( (__m128i*)(pSrc1 + j) ) );
+
+        vdst = _mm_mullo_epi32( vsrc0, vw0 );
+        vdst = _mm_add_epi32( vdst, _mm_mullo_epi32( vsrc1, vw1 ) );
+
+        vdst = _mm_add_epi32( vdst, voffset );
+        vdst = _mm_srai_epi32( vdst, shift );
+        vdst = _mm_packs_epi32( vdst, vdst );
+        _mm_storel_epi64( (__m128i*)(pDst + j), vdst );
+      }
+      pDst += strideDst;
+      pSrc0 += strideSrc0;
+      pSrc1 += strideSrc1;
+    }
+#if USE_AVX2
+  }
+#endif
+}
+#endif
+
 template <X86_VEXT vext>
 void IntraPrediction::_initIntraX86()
 {
@@ -381,6 +449,9 @@ void IntraPrediction::_initIntraX86()
 #if JVET_W0123_TIMD_FUSION && INTRA_TRANS_ENC_OPT
   m_timdBlending = timdBlendingSIMD<vext>;
 #endif
+#if JVET_AC0112_IBC_CIIP && INTRA_TRANS_ENC_OPT
+  m_ibcCiipBlending = ibcCiipBlendingSIMD<vext>;
+#endif
 }
 
 template void IntraPrediction::_initIntraX86<SIMDX86>();
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 097e405266432c6a48fba951322c2c2c8f940654..df750f2b1b61636319ffeba9a548bc661d66f87a 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -3217,6 +3217,9 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
 #if JVET_AA0070_RRIBC
   rribcData(*pu.cu);
 #endif
+#if JVET_AC0112_IBC_LIC
+  cuIbcLicFlag(*pu.cu);
+#endif
 
   if( pu.mergeFlag )
   {
@@ -3231,6 +3234,13 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
   }
   else if (CU::isIBC(*pu.cu))
   {
+#if JVET_AC0112_IBC_CIIP
+    ibcCiipFlag(pu);
+    if (pu.ibcCiipFlag)
+    {
+      ibcCiipIntraIdx(pu);
+    }
+#endif
     pu.interDir = 1;
     pu.cu->affine = false;
     pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF;
@@ -3816,6 +3826,204 @@ void CABACReader::tm_merge_flag(PredictionUnit& pu)
 }
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+void CABACReader::ibcCiipFlag(PredictionUnit& pu)
+{
+  if (!pu.cs->sps->getUseIbcCiip() || ( pu.lx() == 0 && pu.ly() == 0))
+  {
+    pu.ibcCiipFlag = false;
+    return;
+  }
+  if (pu.lwidth() * pu.lheight() < 32 || pu.lwidth() > 32 || pu.lheight() > 32)
+  {
+    pu.ibcCiipFlag = false;
+    return;
+  }
+  if (pu.mergeFlag)
+  {
+    if (pu.cu->skip)
+    {
+      pu.ibcCiipFlag = false;
+      return;
+    }
+    pu.ibcCiipFlag = m_BinDecoder.decodeBin(Ctx::IbcCiipFlag(0));
+  }
+  else
+  {
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType)
+    {
+      pu.ibcCiipFlag = false;
+      return;
+    }
+#endif
+#if JVET_AC0112_IBC_LIC
+    if (pu.cu->ibcLicFlag)
+    {
+      pu.ibcCiipFlag = false;
+      return;
+    }
+#endif
+    if (pu.cs->slice->getSliceType() != I_SLICE)
+    {
+      pu.ibcCiipFlag = false;
+      return;
+    }
+    pu.ibcCiipFlag = m_BinDecoder.decodeBin(Ctx::IbcCiipFlag(1));
+  }
+}
+
+void CABACReader::ibcCiipIntraIdx(PredictionUnit& pu)
+{
+  pu.ibcCiipIntraIdx = m_BinDecoder.decodeBin( Ctx::IbcCiipIntraIdx() );
+}
+#endif
+
+#if JVET_AC0112_IBC_GPM
+void CABACReader::ibcGpmFlag(PredictionUnit& pu)
+{
+  if (!pu.cs->sps->getUseIbcGpm() || (pu.lx() == 0 && pu.ly() == 0))
+  {
+    pu.ibcGpmFlag = false;
+    return;
+  }
+  if (pu.lwidth() < 8 || pu.lheight() < 8 || pu.lwidth() > 32 || pu.lheight() > 32)
+  {
+    pu.ibcGpmFlag = false;
+    return;
+  }
+  pu.ibcGpmFlag = (m_BinDecoder.decodeBin(Ctx::IbcGpmFlag()));
+}
+
+void CABACReader::ibcGpmMergeIdx(PredictionUnit& pu)
+{
+  uint32_t splitDir = 0;
+  bool splitDirFirstSet = m_BinDecoder.decodeBin( Ctx::IbcGpmSplitDirSetFlag() );
+  if (splitDirFirstSet)
+  {
+    int splitDirIdx = m_BinDecoder.decodeBinsEP(3);
+    splitDir = g_ibcGpmFirstSetSplitDir[splitDirIdx];
+  }
+  else
+  {
+    xReadTruncBinCode(splitDir, IBC_GPM_MAX_SPLIT_DIR_SECOND_SET_NUM);
+    uint8_t prefix = splitDir;
+    splitDir++;
+    for (uint8_t i = 0; i < GEO_NUM_PARTITION_MODE && splitDir != 0; i++)
+    {
+      if (!g_ibcGpmSecondSetSplitDir[i])
+      {
+        prefix++;
+      }
+      else
+      {
+        splitDir--;
+      }
+    }
+    splitDir = prefix;
+  }
+  pu.ibcGpmSplitDir = splitDir;
+
+  bool isIntra0 = m_BinDecoder.decodeBin( Ctx::IbcGpmIntraFlag() ) ? true : false;
+  bool isIntra1 = isIntra0 ? false : true;
+
+  const int maxNumIbcGpmCand = pu.cs->sps->getMaxNumIBCMergeCand();
+  int numCandminus2 = maxNumIbcGpmCand - 2;
+  int mergeCand0 = 0;
+  int mergeCand1 = 0;
+  if (isIntra0)
+  {
+    mergeCand0 = IBC_GPM_MAX_NUM_UNI_CANDS + unary_max_eqprob(IBC_GPM_MAX_NUM_INTRA_CANDS-1);
+  }
+  else if (numCandminus2 >= 0)
+  {
+    if (m_BinDecoder.decodeBin(Ctx::MergeIdx()))
+    {
+      mergeCand0 += unary_max_eqprob(numCandminus2) + 1;
+    }
+  }
+  if (isIntra1)
+  {
+    mergeCand1 = IBC_GPM_MAX_NUM_UNI_CANDS + unary_max_eqprob(IBC_GPM_MAX_NUM_INTRA_CANDS-1);
+  }
+  else if (numCandminus2 >= 0)
+  {
+    if (m_BinDecoder.decodeBin(Ctx::MergeIdx()))
+    {
+      mergeCand1 += unary_max_eqprob(numCandminus2) + 1;
+    }
+  }
+  pu.ibcGpmMergeIdx0 = mergeCand0;
+  pu.ibcGpmMergeIdx1 = mergeCand1;
+}
+
+void CABACReader::ibcGpmAdaptBlendIdx(PredictionUnit& pu)
+{
+  if (IBC_GPM_NUM_BLENDING == 1)
+  {
+    pu.ibcGpmBldIdx = 0;
+    return;
+  }
+  int bin0 = m_BinDecoder.decodeBin(Ctx::IbcGpmBldIdx(0));
+  if (bin0 == 1)
+  {
+    pu.ibcGpmBldIdx = 0;
+  }
+  else
+  {
+    int bin1 = m_BinDecoder.decodeBin(Ctx::IbcGpmBldIdx(1));
+    if (bin1 == 0)
+    {
+      int bin2 = m_BinDecoder.decodeBin(Ctx::IbcGpmBldIdx(3));
+      if (bin2 == 0)
+      {
+        pu.ibcGpmBldIdx = 4;
+      }
+      else
+      {
+        pu.ibcGpmBldIdx = 3;
+      }
+    }
+    else
+    {
+      int bin2 = m_BinDecoder.decodeBin(Ctx::IbcGpmBldIdx(2));
+      if (bin2 == 0)
+      {
+        pu.ibcGpmBldIdx = 1;
+      }
+      else
+      {
+        pu.ibcGpmBldIdx = 2;
+      }
+    }
+  }
+}
+#endif
+
+#if JVET_AC0112_IBC_LIC
+void CABACReader::cuIbcLicFlag( CodingUnit& cu )
+{
+  if (!cu.cs->sps->getUseIbcLic() || !CU::isIBC(cu) || cu.firstPU->mergeFlag)
+  {
+    cu.ibcLicFlag = false;
+    return;
+  }
+#if JVET_AA0070_RRIBC
+  if (cu.rribcFlipType > 0)
+  {
+    cu.ibcLicFlag = false;
+    return;
+  }
+#endif
+  if (cu.lwidth() * cu.lheight() < 32 || cu.lwidth() * cu.lheight() > 256)
+  {
+    cu.ibcLicFlag = false;
+    return;
+  }
+  cu.ibcLicFlag = m_BinDecoder.decodeBin( Ctx::IbcLicFlag() );
+}
+#endif
+
 #if JVET_X0049_ADAPT_DMVR
 void CABACReader::bm_merge_flag(PredictionUnit& pu)
 {
@@ -3870,6 +4078,34 @@ void CABACReader::merge_data( PredictionUnit& pu )
 #if JVET_AA0061_IBC_MBVD
     }
 #endif
+#endif
+#if JVET_AC0112_IBC_CIIP
+    ibcCiipFlag(pu);
+    if (pu.ibcCiipFlag)
+    {
+      ibcCiipIntraIdx(pu);
+    }
+#endif
+#if JVET_AC0112_IBC_GPM
+#if JVET_AC0112_IBC_CIIP && JVET_AA0061_IBC_MBVD
+    if (!pu.ibcMbvdMergeFlag && !pu.ibcCiipFlag)
+#else
+#if JVET_AA0061_IBC_MBVD
+    if (!pu.ibcMbvdMergeFlag)
+#else
+#if JVET_AC0112_IBC_CIIP
+    if (!pu.ibcCiipFlag)
+#endif
+#endif
+#endif
+    {
+      ibcGpmFlag(pu);
+      if (pu.ibcGpmFlag)
+      {
+        ibcGpmMergeIdx(pu);
+        ibcGpmAdaptBlendIdx(pu);
+      }
+    }
 #endif
     merge_idx(pu);
     return;
@@ -4238,6 +4474,13 @@ void CABACReader::merge_idx( PredictionUnit& pu )
     {
       return;
     }
+#endif
+#if JVET_AC0112_IBC_GPM
+    if (pu.ibcGpmFlag)
+    {
+      pu.mergeIdx = pu.ibcGpmMergeIdx0 < IBC_GPM_MAX_NUM_UNI_CANDS ? pu.ibcGpmMergeIdx0 : pu.ibcGpmMergeIdx1;
+      return;
+    }
 #endif
     numCandminus1 = int(pu.cs->sps->getMaxNumIBCMergeCand()) - 1;
   }
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index 50ca36be866ada5c4349cbe409ece8afbed4ab7d..70d4fb4463637f57dd6020df0326a7b2f93196b6 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -164,6 +164,18 @@ public:
 #if JVET_AA0061_IBC_MBVD
   void        ibcMbvdData             ( PredictionUnit&               pu );
 #endif
+#if JVET_AC0112_IBC_CIIP
+  void        ibcCiipFlag               ( PredictionUnit&               pu );
+  void        ibcCiipIntraIdx           ( PredictionUnit&               pu );
+#endif
+#if JVET_AC0112_IBC_GPM
+  void        ibcGpmFlag                ( PredictionUnit&               pu );
+  void        ibcGpmMergeIdx            ( PredictionUnit&               pu );
+  void        ibcGpmAdaptBlendIdx       ( PredictionUnit&               pu );
+#endif
+#if JVET_AC0112_IBC_LIC
+  void        cuIbcLicFlag              ( CodingUnit&                   cu );
+#endif
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   void        tm_merge_flag             ( PredictionUnit&               pu );
 #endif
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 2c182ea136329c35543eec873c2d2dd56fe78dc6..b0680ffa154ac45c2c8e2c30c386d7e0435db74c 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -1288,6 +1288,12 @@ void DecCu::xReconInter(CodingUnit &cu)
 #endif
 #endif
   }
+#if JVET_AC0112_IBC_GPM
+  else if (cu.firstPU->ibcGpmFlag)
+  {
+    m_pcInterPred->motionCompensationIbcGpm(cu, m_ibcMrgCtx, m_pcIntraPred);
+  }
+#endif
   else
   {
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
@@ -1309,7 +1315,41 @@ void DecCu::xReconInter(CodingUnit &cu)
       }
     }
 #endif
+
+#if JVET_AC0112_IBC_CIIP
+    uint8_t savedIntraDir[2] = {cu.firstPU->intraDir[0], cu.firstPU->intraDir[1]};
+    if (CU::isIBC(cu) && cu.firstPU->ibcCiipFlag)
+    {
+      uint8_t ibcCiipIntraList[IBC_CIIP_MAX_NUM_INTRA_CANDS] = {PLANAR_IDX, HOR_IDX};
+      m_pcIntraPred->deriveDimdMode(cu.cs->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+      cu.timdMode = m_pcIntraPred->deriveTimdMode(cu.cs->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+      ibcCiipIntraList[0] = MAP131TO67(cu.timdMode);
+      ibcCiipIntraList[1] = ibcCiipIntraList[0] == HOR_IDX ? PLANAR_IDX : HOR_IDX;
+      if (cu.firstPU->mergeFlag && cu.firstPU->ibcCiipIntraIdx > 0)
+      {
+        const PredictionUnit *puBv = cu.cs->getPURestricted(cu.lumaPos().offset(cu.firstPU->bv.getHor(), cu.firstPU->bv.getVer()), *cu.firstPU, cu.chType);
+        uint8_t intraDir = puBv ? puBv->getIpmInfo(cu.lumaPos().offset(cu.firstPU->bv.getHor(), cu.firstPU->bv.getVer())) : PLANAR_IDX;
+        if (intraDir != ibcCiipIntraList[0])
+        {
+          ibcCiipIntraList[1] = intraDir;
+        }
+        else
+        {
+          ibcCiipIntraList[1] = ibcCiipIntraList[0] == PLANAR_IDX ? HOR_IDX : PLANAR_IDX;
+        }
+      }
+      cu.firstPU->intraDir[0] = ibcCiipIntraList[cu.firstPU->ibcCiipIntraIdx];
+      cu.firstPU->intraDir[1] = cu.firstPU->intraDir[0];
+    }
+#endif
     m_pcIntraPred->geneIntrainterPred(cu, m_ciipBuffer);
+#if JVET_AC0112_IBC_CIIP
+    if (CU::isIBC(cu) && cu.firstPU->ibcCiipFlag)
+    {
+      cu.firstPU->intraDir[0] = savedIntraDir[0];
+      cu.firstPU->intraDir[1] = savedIntraDir[1];
+    }
+#endif
 
     // inter prediction
     CHECK(CU::isIBC(cu) && cu.firstPU->ciipFlag, "IBC and Ciip cannot be used together");
@@ -1336,6 +1376,22 @@ void DecCu::xReconInter(CodingUnit &cu)
   }
   if (cu.Y().valid())
   {
+#if JVET_AC0112_IBC_CIIP
+    if (CU::isIBC(cu) && cu.firstPU->ibcCiipFlag)
+    {
+      const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, cu.Y().width, cu.Y().height ) );
+      m_pcIntraPred->geneWeightedPred( COMPONENT_Y, cu.cs->getPredBuf( *cu.firstPU ).Y(), *cu.firstPU, cu.cs->getPredBuf( *cu.firstPU ).Y(), m_ciipBuffer.getBuf( localUnitArea.Y() ) );
+#if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
+      if( isChromaEnabled( cu.chromaFormat ) && cu.Cb().valid())
+#else
+      if( isChromaEnabled( cu.chromaFormat ) && cu.Cb().valid() && cu.chromaSize().width > 2 )
+#endif
+      {
+        m_pcIntraPred->geneWeightedPred( COMPONENT_Cb, cu.cs->getPredBuf( *cu.firstPU ).Cb(), *cu.firstPU, cu.cs->getPredBuf( *cu.firstPU ).Cb(), m_ciipBuffer.getBuf( localUnitArea.Cb() ) );
+        m_pcIntraPred->geneWeightedPred( COMPONENT_Cr, cu.cs->getPredBuf( *cu.firstPU ).Cr(), *cu.firstPU, cu.cs->getPredBuf( *cu.firstPU ).Cr(), m_ciipBuffer.getBuf( localUnitArea.Cr() ) );
+      }
+    }
+#endif
     bool isIbcSmallBlk = CU::isIBC(cu) && (cu.lwidth() * cu.lheight() <= 16);
     CU::saveMotionInHMVP( cu, isIbcSmallBlk );
   }
@@ -2086,7 +2142,13 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
               {
 #if JVET_Z0075_IBC_HMVP_ENLARGE
                 PU::getIBCMergeCandidates(pu, mrgCtx);
+#if JVET_AC0112_IBC_LIC && !JVET_AA0070_RRIBC
+                pu.ibcMbvdMergeFlag = false;
+#endif
                 m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+#if JVET_AC0112_IBC_LIC && !JVET_AA0070_RRIBC
+                pu.ibcMbvdMergeFlag = true;
+#endif
 #else
                 PU::getIBCMergeCandidates(pu, mrgCtx, (((fPosIBCBaseIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE + 1) * ADAPTIVE_IBC_SUB_GROUP_SIZE < pu.cs->sps->getMaxNumIBCMergeCand()) || (fPosIBCBaseIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE) == 0) ? fPosIBCBaseIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE * ADAPTIVE_IBC_SUB_GROUP_SIZE + ADAPTIVE_IBC_SUB_GROUP_SIZE - 1 : fPosIBCBaseIdx);
                 m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, fPosIBCBaseIdx);
@@ -2123,6 +2185,12 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 #endif
                 PU::getIBCMergeCandidates(pu, mrgCtx);
                 m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+#if JVET_AC0112_IBC_GPM && JVET_AA0070_RRIBC
+                if (pu.ibcGpmFlag)
+                {
+                  m_pcInterPred->adjustIbcMergeRribcCand(pu, mrgCtx, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+                }
+#endif
                 pu.mergeIdx = mrgCandIdx;
 #else
                 PU::getIBCMergeCandidates(pu, mrgCtx, (((pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE + 1) * ADAPTIVE_IBC_SUB_GROUP_SIZE < pu.cs->sps->getMaxNumIBCMergeCand()) || (pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE) == 0) ? pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE * ADAPTIVE_IBC_SUB_GROUP_SIZE + ADAPTIVE_IBC_SUB_GROUP_SIZE - 1 : pu.mergeIdx);
@@ -2132,6 +2200,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
               else
 #endif
                 PU::getIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx);
+#if JVET_AC0112_IBC_GPM
+              m_ibcMrgCtx = mrgCtx;
+#endif
 #if JVET_AA0061_IBC_MBVD
             }
 #endif
diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h
index 25ddddfe96f2fa0cc076ef405fc35576efa47642..3b13c88f53e47d753a83cde4c4196afea2a5a5e8 100644
--- a/source/Lib/DecoderLib/DecCu.h
+++ b/source/Lib/DecoderLib/DecCu.h
@@ -122,6 +122,9 @@ private:
   MergeCtx          m_geoTmMrgCtx0, m_geoTmMrgCtx1;
 #endif
 #endif
+#if JVET_AC0112_IBC_GPM
+  MergeCtx          m_ibcMrgCtx;
+#endif
 };
 
 //! \}
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index dab338c57276a8f52434fb4ac98eee630a2de582..68bcbc4160e713d746593ab00778df27b87aca8e 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2560,6 +2560,15 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     pcSPS->setMaxNumIBCMergeCand(IBC_MRG_MAX_NUM_CANDS - uiCode);
 #if JVET_AA0061_IBC_MBVD
     READ_FLAG( uiCode, "sps_ibc_mbvd_enabled_flag" );                   pcSPS->setUseIbcMbvd             ( uiCode != 0 );
+#endif
+#if JVET_AC0112_IBC_CIIP
+    READ_FLAG( uiCode, "sps_ibc_ciip_enabled_flag" );                   pcSPS->setUseIbcCiip             ( uiCode != 0 );
+#endif
+#if JVET_AC0112_IBC_GPM
+    READ_FLAG( uiCode, "sps_ibc_gpm_enabled_flag" );                    pcSPS->setUseIbcGpm              ( uiCode != 0 );
+#endif
+#if JVET_AC0112_IBC_LIC
+    READ_FLAG( uiCode, "sps_ibc_lic_enabled_flag" );                    pcSPS->setUseIbcLic              ( uiCode != 0 );
 #endif
   }
   else
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index bf3e32091980b0e324d849c803baff64eff2887e..a99b0b40487963bfcd8f15833b678ed15e2245ef 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -2854,6 +2854,9 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu )
   }
 #if JVET_AA0070_RRIBC
   rribcData(*pu.cu);
+#endif
+#if JVET_AC0112_IBC_LIC
+  cuIbcLicFlag(*pu.cu);
 #endif
   if( pu.mergeFlag )
   {
@@ -2872,6 +2875,13 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu )
   }
   else if (CU::isIBC(*pu.cu))
   {
+#if JVET_AC0112_IBC_CIIP
+    ibcCiipFlag(pu);
+    if (pu.ibcCiipFlag)
+    {
+      ibcCiipIntraIdx(pu);
+    }
+#endif
     ref_idx(pu, REF_PIC_LIST_0);
     Mv mvd = pu.mvd[REF_PIC_LIST_0];
     mvd.changeIbcPrecInternal2Amvr(pu.cu->imv);
@@ -3439,6 +3449,175 @@ void CABACWriter::tm_merge_flag(const PredictionUnit& pu)
 }
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+void CABACWriter::ibcCiipFlag(const PredictionUnit& pu)
+{
+  if (!pu.cs->sps->getUseIbcCiip() || (pu.lx() == 0 && pu.ly() == 0))
+  {
+    return;
+  }
+  if (pu.lwidth() * pu.lheight() < 32 || pu.lwidth() > 32 || pu.lheight() > 32)
+  {
+    return;
+  }
+  if (pu.mergeFlag)
+  {
+    if (pu.cu->skip)
+    {
+      return;
+    }
+    m_BinEncoder.encodeBin(pu.ibcCiipFlag, Ctx::IbcCiipFlag(0));
+  }
+  else
+  {
+  #if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType)
+    {
+      return;
+    }
+  #endif
+  #if JVET_AC0112_IBC_LIC
+    if (pu.cu->ibcLicFlag)
+    {
+      return;
+    }
+  #endif
+    if (pu.cs->slice->getSliceType() != I_SLICE)
+    {
+      return;
+    }
+    m_BinEncoder.encodeBin(pu.ibcCiipFlag, Ctx::IbcCiipFlag(1));
+  }
+}
+
+void CABACWriter::ibcCiipIntraIdx(const PredictionUnit& pu)
+{
+  m_BinEncoder.encodeBin( pu.ibcCiipIntraIdx > 0, Ctx::IbcCiipIntraIdx() );
+}
+#endif
+
+#if JVET_AC0112_IBC_GPM
+void CABACWriter::ibcGpmFlag(const PredictionUnit& pu)
+{
+  if (!pu.cs->sps->getUseIbcGpm() || (pu.lx() == 0 && pu.ly() == 0))
+  {
+    return;
+  }
+  if (pu.lwidth() < 8 || pu.lheight() < 8 || pu.lwidth() > 32 || pu.lheight() > 32)
+  {
+    return;
+  }
+  m_BinEncoder.encodeBin(pu.ibcGpmFlag, Ctx::IbcGpmFlag());
+}
+
+void CABACWriter::ibcGpmMergeIdx(const PredictionUnit& pu)
+{
+  uint8_t splitDir = pu.ibcGpmSplitDir;
+  uint8_t candIdx0 = pu.ibcGpmMergeIdx0;
+  uint8_t candIdx1 = pu.ibcGpmMergeIdx1;
+
+  uint8_t splitDirIdx = 0;
+  if (g_GeoParams[splitDir][0] % 8 == 0)
+  {
+    m_BinEncoder.encodeBin( 1, Ctx::IbcGpmSplitDirSetFlag() );
+    splitDirIdx = g_ibcGpmFirstSetSplitDirToIdx[splitDir];
+    m_BinEncoder.encodeBinsEP(splitDirIdx, 3);
+  }
+  else
+  {
+    m_BinEncoder.encodeBin( 0, Ctx::IbcGpmSplitDirSetFlag() );
+    uint8_t prefix = 0;
+    for (uint8_t i = 0; i < splitDir; i++)
+    {
+      if (!g_ibcGpmSecondSetSplitDir[i])
+      {
+        prefix++;
+      }
+    }
+    splitDirIdx = splitDir - prefix;
+    xWriteTruncBinCode(splitDirIdx, IBC_GPM_MAX_SPLIT_DIR_SECOND_SET_NUM);
+  }
+
+  bool isIntra0 = (pu.ibcGpmMergeIdx0 >= IBC_GPM_MAX_NUM_UNI_CANDS);
+  bool isIntra1 = (pu.ibcGpmMergeIdx1 >= IBC_GPM_MAX_NUM_UNI_CANDS);
+  m_BinEncoder.encodeBin( isIntra0 ? 1 : 0, Ctx::IbcGpmIntraFlag() );
+
+  const int maxNumIbcGpmCand = pu.cs->sps->getMaxNumIBCMergeCand();
+  int numCandminus2 = maxNumIbcGpmCand - 2;
+  if (isIntra0)
+  {
+    unary_max_eqprob(candIdx0 - IBC_GPM_MAX_NUM_UNI_CANDS, IBC_GPM_MAX_NUM_INTRA_CANDS-1);
+  }
+  else if (numCandminus2 >= 0)
+  {
+    m_BinEncoder.encodeBin(candIdx0 == 0 ? 0 : 1, Ctx::MergeIdx());
+    if (candIdx0 > 0)
+    {
+      unary_max_eqprob(candIdx0 - 1, numCandminus2);
+    }
+  }
+  if (isIntra1)
+  {
+    unary_max_eqprob(candIdx1 - IBC_GPM_MAX_NUM_UNI_CANDS, IBC_GPM_MAX_NUM_INTRA_CANDS-1);
+  }
+  else if (numCandminus2 >= 0)
+  {
+    m_BinEncoder.encodeBin(candIdx1 == 0 ? 0 : 1, Ctx::MergeIdx());
+    if (candIdx1 > 0)
+    {
+      unary_max_eqprob(candIdx1 - 1, numCandminus2);
+    }
+  }
+}
+
+void CABACWriter::ibcGpmAdaptBlendIdx(const int flag)
+{
+  if (IBC_GPM_NUM_BLENDING == 1)
+  {
+    return;
+  }
+  if (flag == 0)
+  {
+    m_BinEncoder.encodeBin(1, Ctx::IbcGpmBldIdx(0));
+  }
+  else
+  {
+    m_BinEncoder.encodeBin(0, Ctx::IbcGpmBldIdx(0));
+    if (flag == 2 || flag == 1)
+    {
+      m_BinEncoder.encodeBin(1, Ctx::IbcGpmBldIdx(1));
+      m_BinEncoder.encodeBin(flag == 2, Ctx::IbcGpmBldIdx(2));
+    }
+    else
+    {
+      m_BinEncoder.encodeBin(0, Ctx::IbcGpmBldIdx(1));
+      m_BinEncoder.encodeBin(flag == 3, Ctx::IbcGpmBldIdx(3));
+    }
+  }
+}
+#endif
+
+#if JVET_AC0112_IBC_LIC
+void CABACWriter::cuIbcLicFlag(const CodingUnit& cu)
+{
+  if (!cu.cs->sps->getUseIbcLic() || !CU::isIBC(cu) || cu.firstPU->mergeFlag)
+  {
+    return;
+  }
+#if JVET_AA0070_RRIBC
+  if (cu.rribcFlipType > 0)
+  {
+    return;
+  }
+#endif
+  if (cu.lwidth() * cu.lheight() < 32 || cu.lwidth() * cu.lheight() > 256)
+  {
+    return;
+  }
+  m_BinEncoder.encodeBin(cu.ibcLicFlag ? 1 : 0, Ctx::IbcLicFlag());
+}
+#endif
+
 #if JVET_X0049_ADAPT_DMVR
 void CABACWriter::bm_merge_flag(const PredictionUnit& pu)
 {
@@ -3483,6 +3662,34 @@ void CABACWriter::merge_data(const PredictionUnit& pu)
 #if JVET_AA0061_IBC_MBVD
     }
 #endif
+#endif
+#if JVET_AC0112_IBC_CIIP
+    ibcCiipFlag(pu);
+    if (pu.ibcCiipFlag)
+    {
+      ibcCiipIntraIdx(pu);
+    }
+#endif
+#if JVET_AC0112_IBC_GPM
+#if JVET_AC0112_IBC_CIIP && JVET_AA0061_IBC_MBVD
+    if (!pu.ibcMbvdMergeFlag && !pu.ibcCiipFlag)
+#else
+#if JVET_AA0061_IBC_MBVD
+    if (!pu.ibcMbvdMergeFlag)
+#else
+#if JVET_AC0112_IBC_CIIP
+    if (!pu.ibcCiipFlag)
+#endif
+#endif
+#endif
+    {
+      ibcGpmFlag(pu);
+      if (pu.ibcGpmFlag)
+      {
+        ibcGpmMergeIdx(pu);
+        ibcGpmAdaptBlendIdx(pu.ibcGpmBldIdx);
+      }
+    }
 #endif
     merge_idx(pu);
     return;
@@ -3877,17 +4084,21 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
 #endif
 #endif
     if (pu.cu->predMode == MODE_IBC)
-#if JVET_AA0061_IBC_MBVD
     {
+#if JVET_AA0061_IBC_MBVD
       if (pu.ibcMbvdMergeFlag)
       {
         return;
       }
+#endif
+#if JVET_AC0112_IBC_GPM
+      if (pu.ibcGpmFlag)
+      {
+        return;
+      }
 #endif
       numCandminus1 = int(pu.cs->sps->getMaxNumIBCMergeCand()) - 1;
-#if JVET_AA0061_IBC_MBVD
     }
-#endif
 #if TM_MRG
     else if (pu.tmMergeFlag)
 #if JVET_X0141_CIIP_TIMD_TM
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index d6e0959c3498092642ebd10d59686385cbcf8e17..b059d4f8d8a80ec9fe7a726c152f58c98ee6cfee 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -175,6 +175,18 @@ public:
 #if JVET_AA0061_IBC_MBVD
   void        ibcMbvdData             ( const PredictionUnit&         pu );
 #endif
+#if JVET_AC0112_IBC_CIIP
+  void        ibcCiipFlag               ( const PredictionUnit&         pu );
+  void        ibcCiipIntraIdx           ( const PredictionUnit&         pu );
+#endif
+#if JVET_AC0112_IBC_GPM
+  void        ibcGpmFlag                ( const PredictionUnit&         pu );
+  void        ibcGpmMergeIdx            ( const PredictionUnit&         pu );
+  void        ibcGpmAdaptBlendIdx       ( const int idx );
+#endif
+#if JVET_AC0112_IBC_LIC
+  void        cuIbcLicFlag              (const CodingUnit& cu );
+#endif
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   void        tm_merge_flag             ( const PredictionUnit&         pu);
 #endif
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index f0847b15450be388fd6d90fe3ab917513ab38281..d91eb363dc2ac24f6df20fd1947e7eba1b650c84 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -506,6 +506,15 @@ protected:
 #if JVET_AA0061_IBC_MBVD
   bool      m_ibcMbvd;
 #endif
+#if JVET_AC0112_IBC_CIIP
+  bool      m_ibcCiip;
+#endif
+#if JVET_AC0112_IBC_GPM
+  bool      m_ibcGpm;
+#endif
+#if JVET_AC0112_IBC_LIC
+  bool      m_ibcLic;
+#endif
 
   bool      m_wrapAround;
   unsigned  m_wrapAroundOffset;
@@ -1382,6 +1391,18 @@ public:
   void      setIbcMbvd                      ( bool b )       { m_ibcMbvd = b; }
   bool      getIbcMbvd                      ()         const { return m_ibcMbvd; }
 #endif
+#if JVET_AC0112_IBC_CIIP
+  void      setIbcCiip                      ( bool b )       { m_ibcCiip = b; }
+  bool      getIbcCiip                      ()         const { return m_ibcCiip; }
+#endif
+#if JVET_AC0112_IBC_GPM
+  void      setIbcGpm                       ( bool b )       { m_ibcGpm = b; }
+  bool      getIbcGpm                       ()         const { return m_ibcGpm; }
+#endif
+#if JVET_AC0112_IBC_LIC
+  void      setIbcLic                       ( bool b )       { m_ibcLic = b; }
+  bool      getIbcLic                       ()         const { return m_ibcLic; }
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   void      setUseDMVDMode                  (bool b)         { m_DMVDMode = b; }
   bool      getUseDMVDMode                  ()         const { return m_DMVDMode; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 369e53634fa5b985cf70996795c9d15d6ae5ff68..7e2326a898e11091bdec5efc7082548eb2662791 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -10838,6 +10838,32 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
   uint32_t ibcMbvdValidNum[IBC_MBVD_BASE_NUM] = { 0 };
 #endif
 
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+  const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
+  PelUnitBuf intraPredBuf[NUM_LUMA_MODE];
+  bool intraPredBufSet[NUM_LUMA_MODE] = {false, };
+#endif
+#if JVET_AC0112_IBC_CIIP
+  bool testIbcCiip = tempCS->sps->getUseIbcCiip() && (tempCS->area.lwidth() * tempCS->area.lheight() >= 32) && tempCS->area.lwidth() <= 32 && tempCS->area.lheight() <= 32 && (tempCS->area.lx() > 0 || tempCS->area.ly() > 0);
+  int wIbc = 13, wIntra = 3, shift = 4;
+  PelBuf ibcCiipBuf = m_ciipBuffer[1].getBuf(localUnitArea.Y());
+  int ibcCiipIntraList[IBC_CIIP_MAX_NUM_INTRA_CANDS];
+  double ibcCiipBestSatdCost = MAX_DOUBLE;
+  int ibcCiipBestMergeCand = 0;
+  int ibcCiipBestIntraCand = 0;
+#endif
+#if JVET_AC0112_IBC_GPM
+  MergeCtx mergeCtxIbcGeo;
+  int skipCandNum[IBC_MRG_MAX_NUM_CANDS] = {0, };
+#if JVET_Z0084_IBC_TM && IBC_TM_MRG
+  MergeCtx mergeCtxTmIbcGeo;
+  int skipCandNumTm[IBC_MRG_MAX_NUM_CANDS<<1] = {0, };
+#endif
+  DistParam distParamSad;
+  Distortion sadIntraWholeBlk[NUM_LUMA_MODE];
+  uint8_t ibcGpmIntraCandList[GEO_NUM_PARTITION_MODE][2][IBC_GPM_MAX_NUM_INTRA_CANDS];
+#endif
+
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
@@ -10861,6 +10887,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     cu.LICFlag = false;
 #endif
     cu.geoFlag = false;
+#if JVET_AC0112_IBC_LIC
+    cu.ibcLicFlag = false;
+#endif
 #if JVET_AA0070_RRIBC
     cu.rribcFlipType = 0;
     pu.mergeFlag = true;
@@ -10938,25 +10967,71 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     numMrgSATDCand += 2;
   }
   numMrgSATDCand = std::min(numMrgSATDCand, (const int)(mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand));
+#if JVET_AC0112_IBC_CIIP
+  static_vector<ModeIbcInfo, ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)>  rdModeList((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM);
+  for (unsigned i = 0; i < ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM); i++)
+  {
+    rdModeList[i].mergeCand = i;
+    rdModeList[i].isCIIP = false;
+#if JVET_AC0112_IBC_GPM
+    rdModeList[i].isIbcGpm = false;
+#endif
+  }
+#else
+#if JVET_AC0112_IBC_GPM
+  static_vector<ModeIbcInfo, ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)>  rdModeList((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM);
+  for (unsigned i = 0; i < ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM); i++)
+  {
+    rdModeList[i].mergeCand = i;
+    rdModeList[i].isIbcGpm = false;
+  }
+#else
   static_vector<unsigned, ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)>  rdModeList((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM);
   for (unsigned i = 0; i < ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM); i++)
   {
     rdModeList[i] = i;
   }
+#endif
+#endif
 
   static_vector<double, ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)>  candCostList(((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM), MAX_DOUBLE);
 #else
   int candHasNoResidual[IBC_MRG_MAX_NUM_CANDS<<1] = {0,};
   bool                                                 bestIsSkip = false;
   unsigned                                             numMrgSATDCand = mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand;
+#if JVET_AC0112_IBC_CIIP
+  static_vector<ModeIbcInfo, ((IBC_MRG_MAX_NUM_CANDS<<1)+2)>  rdModeList((IBC_MRG_MAX_NUM_CANDS<<1)+2);
+  for (unsigned i = 0; i < (IBC_MRG_MAX_NUM_CANDS<<1)+2; i++)
+  {
+    rdModeList[i].mergeCand = i;
+    rdModeList[i].isCIIP = false;
+#if JVET_AC0112_IBC_GPM
+    rdModeList[i].isIbcGpm = false;
+#endif
+  }
+#else
+#if JVET_AC0112_IBC_GPM
+  static_vector<ModeIbcInfo, ((IBC_MRG_MAX_NUM_CANDS<<1)+2)>  rdModeList((IBC_MRG_MAX_NUM_CANDS<<1)+2);
+  for (unsigned i = 0; i < (IBC_MRG_MAX_NUM_CANDS<<1)+2; i++)
+  {
+    rdModeList[i].mergeCand = i;
+    rdModeList[i].isIbcGpm = false;
+  }
+#else
   static_vector<unsigned, (IBC_MRG_MAX_NUM_CANDS<<1)>  rdModeList(IBC_MRG_MAX_NUM_CANDS<<1);
   for (unsigned i = 0; i < IBC_MRG_MAX_NUM_CANDS<<1; i++)
   {
     rdModeList[i] = i;
   }
+#endif
+#endif
 
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+  static_vector<double, ((IBC_MRG_MAX_NUM_CANDS<<1)+2)>  candCostList((IBC_MRG_MAX_NUM_CANDS<<1)+2, MAX_DOUBLE);
+#else
   static_vector<double, (IBC_MRG_MAX_NUM_CANDS<<1)>  candCostList(IBC_MRG_MAX_NUM_CANDS<<1, MAX_DOUBLE);
 #endif
+#endif
 #else
 #if JVET_AA0061_IBC_MBVD
   int candHasNoResidual[MRG_MAX_NUM_CANDS + IBC_MBVD_NUM] = {0,};
@@ -10985,6 +11060,24 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     static_vector<double, MRG_MAX_NUM_CANDS>  candCostList(MRG_MAX_NUM_CANDS, MAX_DOUBLE);
 #endif
 #endif
+
+#if JVET_AC0112_IBC_GPM
+  Distortion sadWholeBlk[IBC_MRG_MAX_NUM_CANDS<<1];
+  bool isSkipThisCand[IBC_GPM_MAX_NUM_UNI_CANDS<<1] = {false, };
+  PelUnitBuf ibcPredBuf[IBC_MRG_MAX_NUM_CANDS<<1];
+  static_vector<int, IBC_MRG_MAX_NUM_CANDS<<1> mergeCandList0[GEO_NUM_PARTITION_MODE];
+  static_vector<int, IBC_MRG_MAX_NUM_CANDS<<1> mergeCandList1[GEO_NUM_PARTITION_MODE];
+  static_vector<double, IBC_MRG_MAX_NUM_CANDS<<1> sadCostList0[GEO_NUM_PARTITION_MODE];
+  static_vector<double, IBC_MRG_MAX_NUM_CANDS<<1> sadCostList1[GEO_NUM_PARTITION_MODE];
+  int ibcGpmCandNumValid = 0;
+  PelUnitBuf geoCombinations[IBC_GPM_MAX_TRY_WEIGHTED_SAD*IBC_GPM_NUM_BLENDING+1];
+  static_vector<int, IBC_GPM_MAX_NUM_INTRA_CANDS> intraCandList0[GEO_NUM_PARTITION_MODE];
+  static_vector<int, IBC_GPM_MAX_NUM_INTRA_CANDS> intraCandList1[GEO_NUM_PARTITION_MODE];
+  static_vector<double, IBC_GPM_MAX_NUM_INTRA_CANDS> intraSadCostList0[GEO_NUM_PARTITION_MODE];
+  static_vector<double, IBC_GPM_MAX_NUM_INTRA_CANDS> intraSadCostList1[GEO_NUM_PARTITION_MODE];
+  bool testIbcGpm = tempCS->sps->getUseIbcGpm() && (tempCS->area.lx() > 0 || tempCS->area.ly() > 0);
+#endif
+
     // 1. Pass: get SATD-cost for selected candidates and reduce their count
     {
       const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( );
@@ -11001,6 +11094,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       cu.mmvdSkip = false;
 #if INTER_LIC
       cu.LICFlag = false;
+#endif
+#if JVET_AC0112_IBC_LIC
+      cu.ibcLicFlag = false;
 #endif
       cu.geoFlag = false;
 
@@ -11013,6 +11109,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       Picture* refPic = pu.cu->slice->getPic();
       const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]);
       const Pel*        piRefSrch = refBuf.buf;
+#if JVET_AC0112_IBC_LIC
+      PelBuf predBuf = tempCS->getPredBuf(pu.Y());
+#endif
 #if JVET_AA0070_RRIBC
       pu.cu->rribcFlipType = 0;
       const CompArea &area = cu.blocks[COMPONENT_Y];
@@ -11047,6 +11146,97 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
         m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
 #endif
 
+#if JVET_AC0112_IBC_GPM
+      int dimdMode = -1;
+      int timdMode = -1;
+#endif
+#if JVET_AC0112_IBC_CIIP
+      if (testIbcCiip)
+      {
+        IntraPrediction::deriveDimdMode(tempCS->picture->getRecoBuf(tempCS->area.Y()), tempCS->area.Y(), cu);
+        cu.timdMode = m_pcIntraSearch->deriveTimdMode(tempCS->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+        ibcCiipIntraList[0] = MAP131TO67(cu.timdMode);
+#if JVET_AC0112_IBC_GPM
+        dimdMode = cu.dimdMode;
+        timdMode = cu.timdMode;
+#endif
+        pu.ibcCiipFlag = true;
+        ibcCiipIntraList[1] = HOR_IDX;
+        pu.intraDir[0] = ibcCiipIntraList[0];
+        m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), true);
+        m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+        intraPredBuf[pu.intraDir[0]] = m_acMergeBuffer[pu.intraDir[0] + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+        m_pcIntraSearch->predIntraAng(COMPONENT_Y, intraPredBuf[pu.intraDir[0]].Y(), pu);
+        intraPredBufSet[pu.intraDir[0]] = true;
+        pu.ibcCiipFlag = false;
+      }
+#endif
+#if JVET_AC0112_IBC_GPM
+      if (pu.lwidth() < 8 || pu.lheight() < 8 || pu.lwidth() > 32 || pu.lheight() > 32)
+      {
+        testIbcGpm &= false;
+      }
+      if (testIbcGpm)
+      {
+#if JVET_AA0070_RRIBC
+        m_pcRdCost->setDistParam(distParamSad, tmpOrgLuma, m_acMergeBuffer[0].Y().buf, m_acMergeBuffer[0].Y().stride, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+#else
+        if (tempCS->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
+        {
+          const CompArea &area = cu.blocks[COMPONENT_Y];
+          CompArea    tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
+          PelBuf tmpLuma = m_tmpStorageLCU->getBuf(tmpArea);
+          tmpLuma.rspSignal( tempCS->getOrgBuf().Y(), m_pcReshape->getFwdLUT() );
+          m_pcRdCost->setDistParam(distParamSad, tmpLuma, m_acMergeBuffer[0].Y().buf, m_acMergeBuffer[0].Y().stride, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+        }
+        else
+        {
+          m_pcRdCost->setDistParam(distParamSad, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y().buf, m_acMergeBuffer[0].Y().stride, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+        }
+#endif
+        if (dimdMode == -1 || timdMode == -1)
+        {
+          IntraPrediction::deriveDimdMode(tempCS->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+          dimdMode = cu.dimdMode;
+          cu.timdMode = m_pcIntraSearch->deriveTimdMode(tempCS->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+          timdMode = cu.timdMode;
+        }
+        pu.ibcGpmFlag = true;
+        m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), true);
+        for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
+        {
+          if (!g_ibcGpmSecondSetSplitDir[splitDir] && g_GeoParams[splitDir][0] % 8 != 0)
+          {
+            continue;
+          }
+          for (int partIdx = 0; partIdx < 2; partIdx++)
+          {
+            PU::getGeoIntraMPMs(pu, ibcGpmIntraCandList[splitDir][partIdx], splitDir, g_geoTmShape[partIdx][g_GeoParams[splitDir][0]]
+#if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
+                                , (splitDir == 0 && partIdx == 0)
+#endif
+                                );
+            for (int intraIdx = 0; intraIdx < IBC_GPM_MAX_NUM_INTRA_CANDS; intraIdx++)
+            {
+              uint8_t intraCand = ibcGpmIntraCandList[splitDir][partIdx][intraIdx];
+              if (!intraPredBufSet[intraCand])
+              {
+                intraPredBufSet[intraCand] = true;
+                pu.intraDir[0] = intraCand;
+                intraPredBuf[intraCand] = m_acMergeBuffer[intraCand + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+                m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+                m_pcIntraSearch->predIntraAng(COMPONENT_Y, intraPredBuf[intraCand].Y(), pu);
+              }
+              distParamSad.cur.buf = intraPredBuf[intraCand].Y().buf;
+              distParamSad.cur.stride = intraPredBuf[intraCand].Y().stride;
+              sadIntraWholeBlk[intraCand] = distParamSad.distFunc(distParamSad);
+            }
+          }
+        }
+        pu.ibcGpmFlag = false;
+      }
+#endif
+
       int refStride = refBuf.stride;
 #if !JVET_Y0058_IBC_LIST_MODIFY
       const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
@@ -11070,6 +11260,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       for (unsigned int mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; mergeCand++)
       {
         mergeCtx.setMergeInfo(pu, mergeCand); // set bv info in merge mode
+#if JVET_AC0112_IBC_GPM
+        int mergeCandIbcGpm = mergeCand - skipCandNum[mergeCand > 0 ? mergeCand - 1 : 0];
+#endif
 
         int xPred = pu.bv.getHor();
         int yPred = pu.bv.getVer();
@@ -11086,10 +11279,29 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
           numValidBv--;
 #if JVET_AA0061_IBC_MBVD && !JVET_AA0070_RRIBC
           numValidBvIBC--;
+#endif
+#if JVET_AC0112_IBC_GPM
+          isSkipThisCand[mergeCandIbcGpm] = true;
 #endif
           continue;
         }
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+#if JVET_AC0112_IBC_GPM
+#if JVET_AA0070_RRIBC
+        if (pu.cu->rribcFlipType > 0)
+        {
+          isSkipThisCand[mergeCandIbcGpm] = true;
+          skipCandNum[mergeCand] = mergeCand > 0 ? skipCandNum[mergeCand - 1] + 1 : 1;
+        }
+        else
+#endif
+        {
+          skipCandNum[mergeCand] = mergeCand > 0 ? skipCandNum[mergeCand - 1] : 0;
+        }
+#endif
+#else
         PU::spanMotionInfo(pu, mergeCtx);
+#endif
 
 #if JVET_AA0070_RRIBC
         if (pu.cu->rribcFlipType == 0)
@@ -11106,6 +11318,23 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
         }
 #endif
 
+#if JVET_AC0112_IBC_LIC
+        if (pu.cu->ibcLicFlag)
+        {
+          Pel* piPred = predBuf.buf;
+          int predStride = predBuf.stride;
+          int height = predBuf.height;
+          int width = predBuf.width;
+          for (int h = 0; h < height; h++)
+          {
+            memcpy(piPred, piRefSrch + h * refStride + refStride * yPred + xPred, width * sizeof(Pel));
+            piPred += predStride;
+          }
+          m_pcInterSearch->xLocalIlluComp(pu, COMPONENT_Y, pu.bv, predBuf);
+          distParam.cur = predBuf;
+        }
+        else
+#endif
         distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
 
         Distortion sad = distParam.distFunc(distParam);
@@ -11123,15 +11352,128 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
         double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
 
+#if JVET_AC0112_IBC_CIIP
+        if (testIbcCiip)
+        {
+          const PredictionUnit *puBv = pu.cs->getPURestricted(pu.lumaPos().offset(xPred, yPred), pu, pu.chType);
+          int intraDir = puBv ? puBv->getIpmInfo(pu.lumaPos().offset(xPred, yPred)) : PLANAR_IDX;
+          if (intraDir != ibcCiipIntraList[0])
+          {
+            ibcCiipIntraList[1] = intraDir;
+          }
+          else
+          {
+            ibcCiipIntraList[1] = ibcCiipIntraList[0] == PLANAR_IDX ? HOR_IDX : PLANAR_IDX;
+          }
+          intraDir = ibcCiipIntraList[1];
+          if (!intraPredBufSet[intraDir])
+          {
+            pu.ibcCiipFlag = true;
+            pu.intraDir[0] = intraDir;
+            intraPredBufSet[intraDir] = true;
+            intraPredBuf[intraDir] = m_acMergeBuffer[intraDir + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+            m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+            m_pcIntraSearch->predIntraAng(COMPONENT_Y, intraPredBuf[intraDir].Y(), pu);
+            pu.ibcCiipFlag = false;
+          }
+          for (int dirIdx = 0; dirIdx < IBC_CIIP_MAX_NUM_INTRA_CANDS; dirIdx++)
+          {
+            int height = pu.lheight();
+            int width = pu.lwidth();
+            const Pel *pPredIbc = piRefSrch + refStride * yPred + xPred;
+            Pel *pPredDst = ibcCiipBuf.buf;
+            int dstStride = ibcCiipBuf.stride;
+            Pel *pPredIntra = intraPredBuf[ibcCiipIntraList[dirIdx]].Y().buf;
+            int intraStride = intraPredBuf[ibcCiipIntraList[dirIdx]].Y().stride;
+            m_pcIntraSearch->m_ibcCiipBlending(pPredDst, dstStride, pPredIbc, refStride, pPredIntra, intraStride, wIbc, wIntra, shift, width, height);
+
+            distParam.cur.buf = ibcCiipBuf.buf;
+            distParam.cur.stride = ibcCiipBuf.stride;
+
+            Distortion sad2 = distParam.distFunc(distParam);
+            unsigned int bitsCand2 = mergeCand + 1;
+#if JVET_Z0084_IBC_TM
+            if (mergeCand == tempCS->sps->getMaxNumIBCMergeCand() - 1)
+#else
+            if (mergeCand == tempCS->sps->getMaxNumMergeCand() - 1)
+#endif
+            {
+              bitsCand2--;
+            }
+            bitsCand2 += dirIdx + 1;
+            if (dirIdx == IBC_CIIP_MAX_NUM_INTRA_CANDS - 1)
+            {
+              bitsCand2--;
+            }
+            bitsCand2++; // for ibc_mbvd_flag
+            double cost2 = (double)sad2 + (double)bitsCand2 * sqrtLambdaForFirstPass;
+            if (cost2 < ibcCiipBestSatdCost)
+            {
+              ibcCiipBestMergeCand = mergeCand;
+              ibcCiipBestIntraCand = dirIdx;
+              ibcCiipBestSatdCost = cost2;
+            }
+          }
+        }
+#endif
+
+#if JVET_AC0112_IBC_GPM
+#if JVET_AA0070_RRIBC
+        if (pu.cu->rribcFlipType == 0 && testIbcGpm)
+#else
+        if (testIbcGpm)
+#endif
+        {
+          ibcGpmCandNumValid++;
+          distParamSad.cur.buf = piRefSrch + refStride * yPred + xPred;
+          distParamSad.cur.stride = refBuf.stride;
+          ibcPredBuf[mergeCandIbcGpm] = m_acMergeBuffer[mergeCandIbcGpm].getBuf(localUnitArea);
+          ibcPredBuf[mergeCandIbcGpm].bufs[COMPONENT_Y].copyFrom(distParamSad.cur);
+          sadWholeBlk[mergeCandIbcGpm] = distParamSad.distFunc(distParamSad);
+        }
+#endif
+
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_GPM
+        updateCandList(ModeIbcInfo(mergeCand, false, 0, false, 0, 0, 0, 0, 0), cost, rdModeList, candCostList
+         , numMrgSATDCand);
+#else
+        updateCandList(ModeIbcInfo(mergeCand, false, 0), cost, rdModeList, candCostList
+         , numMrgSATDCand);
+#endif
+#else
+#if JVET_AC0112_IBC_GPM
+        updateCandList(ModeIbcInfo(mergeCand, false, 0, 0, 0, 0, 0), cost, rdModeList, candCostList
+         , numMrgSATDCand);
+#else
         updateCandList(mergeCand, cost, rdModeList, candCostList
          , numMrgSATDCand);
+#endif
+#endif
       }
+#if JVET_AC0112_IBC_GPM
+      if (testIbcGpm && mergeCtx.numValidMergeCand > 0)
+      {
+        mergeCtxIbcGeo = mergeCtx;
+#if JVET_AA0070_RRIBC
+        m_pcInterSearch->adjustIbcMergeRribcCand(pu, mergeCtxIbcGeo, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+#endif
+        for (int i = 0; i < skipCandNum[mergeCtx.numValidMergeCand - 1]; i++)
+        {
+          isSkipThisCand[mergeCtx.numValidMergeCand - 1 - i] = true;
+        }
+      }
+#endif
+
 
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
     // Add TM refined candidates
     for (unsigned int mergeCand = 0; mergeCand < mergeCtxTm.numValidMergeCand; mergeCand++)
     {
       mergeCtxTm.setMergeInfo(pu, mergeCand); // set bv info in merge mode
+#if JVET_AC0112_IBC_GPM
+      int mergeCandIbcGpm = mergeCand - skipCandNumTm[mergeCtx.numValidMergeCand + (mergeCand  > 0 ? mergeCand - 1 : 0)];
+#endif
 
       Mv tempBv = pu.bv;
       pu.tmMergeFlag = true;
@@ -11144,6 +11486,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       if (pu.bv == tempBv)
       {
         numValidBv--;
+#if JVET_AC0112_IBC_GPM
+        isSkipThisCand[mergeCtx.numValidMergeCand + mergeCandIbcGpm] = true;
+#endif
         continue;
       }
 
@@ -11159,9 +11504,28 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
       {
         numValidBv--;
+#if JVET_AC0112_IBC_GPM
+        isSkipThisCand[mergeCtx.numValidMergeCand + mergeCandIbcGpm] = true;
+#endif
         continue;
       }
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_GPM
+#if JVET_AC0112_IBC_GPM
+#if JVET_AA0070_RRIBC
+      if (pu.cu->rribcFlipType > 0)
+      {
+        isSkipThisCand[mergeCtx.numValidMergeCand + mergeCandIbcGpm] = true;
+        skipCandNumTm[mergeCtx.numValidMergeCand + mergeCand] = mergeCand > 0 ? skipCandNumTm[mergeCtx.numValidMergeCand + mergeCand - 1] + 1 : 1;
+      }
+      else
+#endif
+      {
+        skipCandNumTm[mergeCtx.numValidMergeCand + mergeCand] = mergeCand > 0 ? skipCandNumTm[mergeCtx.numValidMergeCand + mergeCand - 1] : 0;
+      }
+#endif
+#else
       PU::spanMotionInfo(pu, mergeCtxTm);
+#endif
 
 #if JVET_AA0070_RRIBC
       if (pu.cu->rribcFlipType == 0)
@@ -11176,6 +11540,23 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       {
         m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipV, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
       }
+#endif
+#if JVET_AC0112_IBC_LIC
+      if (pu.cu->ibcLicFlag)
+      {
+        Pel* piPred = predBuf.buf;
+        int predStride = predBuf.stride;
+        int height = predBuf.height;
+        int width = predBuf.width;
+        for (int h = 0; h < height; h++)
+        {
+          memcpy(piPred, piRefSrch + h * refStride + refStride * yPred + xPred, width * sizeof(Pel));
+          piPred += predStride;
+        }
+        m_pcInterSearch->xLocalIlluComp(pu, COMPONENT_Y, pu.bv, predBuf);
+        distParam.cur = predBuf;
+      }
+      else
 #endif
       distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
 
@@ -11190,9 +11571,116 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
       double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
 
+#if JVET_AC0112_IBC_CIIP
+      if (testIbcCiip)
+      {
+        const PredictionUnit *puBv = pu.cs->getPURestricted(pu.lumaPos().offset(xPred, yPred), pu, pu.chType);
+        int intraDir = puBv ? puBv->getIpmInfo(pu.lumaPos().offset(xPred, yPred)) : PLANAR_IDX;
+        if (intraDir != ibcCiipIntraList[0])
+        {
+          ibcCiipIntraList[1] = intraDir;
+        }
+        else
+        {
+          ibcCiipIntraList[1] = ibcCiipIntraList[0] == PLANAR_IDX ? HOR_IDX : PLANAR_IDX;
+        }
+        intraDir = ibcCiipIntraList[1];
+        if (!intraPredBufSet[intraDir])
+        {
+          pu.ibcCiipFlag = true;
+          pu.intraDir[0] = intraDir;
+          intraPredBufSet[intraDir] = true;
+          intraPredBuf[intraDir] = m_acMergeBuffer[intraDir + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+          m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+          m_pcIntraSearch->predIntraAng(COMPONENT_Y, intraPredBuf[intraDir].Y(), pu);
+          pu.ibcCiipFlag = false;
+        }
+        for (int dirIdx = 0; dirIdx < IBC_CIIP_MAX_NUM_INTRA_CANDS; dirIdx++)
+        {
+          int height = pu.lheight();
+          int width = pu.lwidth();
+          const Pel *pPredIbc = piRefSrch + refStride * yPred + xPred;
+          Pel *pPredDst = ibcCiipBuf.buf;
+          int dstStride = ibcCiipBuf.stride;
+          Pel *pPredIntra = intraPredBuf[ibcCiipIntraList[dirIdx]].Y().buf;
+          int intraStride = intraPredBuf[ibcCiipIntraList[dirIdx]].Y().stride;
+          m_pcIntraSearch->m_ibcCiipBlending(pPredDst, dstStride, pPredIbc, refStride, pPredIntra, intraStride, wIbc, wIntra, shift, width, height);
+
+          distParam.cur.buf = ibcCiipBuf.buf;
+          distParam.cur.stride = ibcCiipBuf.stride;
+
+          Distortion sad2 = distParam.distFunc(distParam);
+          unsigned int bitsCand2 = mergeCand + 1;
+#if JVET_Z0084_IBC_TM
+          if (mergeCand == tempCS->sps->getMaxNumIBCMergeCand() - 1)
+#else
+          if (mergeCand == tempCS->sps->getMaxNumMergeCand() - 1)
+#endif
+          {
+            bitsCand2--;
+          }
+          bitsCand2 += dirIdx + 1;
+          if (dirIdx == IBC_CIIP_MAX_NUM_INTRA_CANDS - 1)
+          {
+            bitsCand2--;
+          }
+          bitsCand2++; // for ibc_mbvd_flag
+          double cost2 = (double)sad2 + (double)bitsCand2 * sqrtLambdaForFirstPass;
+          if (cost2 < ibcCiipBestSatdCost)
+          {
+            ibcCiipBestMergeCand = mergeCand+mergeCtx.numValidMergeCand;
+            ibcCiipBestIntraCand = dirIdx;
+            ibcCiipBestSatdCost = cost2;
+          }
+        }
+      }
+#endif
+
+#if JVET_AC0112_IBC_GPM
+#if JVET_AA0070_RRIBC
+      if (pu.cu->rribcFlipType == 0 && testIbcGpm)
+#else
+      if (testIbcGpm)
+#endif
+      {
+        ibcGpmCandNumValid++;
+        distParamSad.cur.buf = piRefSrch + refStride * yPred + xPred;
+        distParamSad.cur.stride = refBuf.stride;
+        ibcPredBuf[mergeCtx.numValidMergeCand + mergeCandIbcGpm] = m_acMergeBuffer[mergeCtx.numValidMergeCand + mergeCandIbcGpm].getBuf(localUnitArea);
+        ibcPredBuf[mergeCtx.numValidMergeCand + mergeCandIbcGpm].bufs[COMPONENT_Y].copyFrom(distParamSad.cur);
+        sadWholeBlk[mergeCtx.numValidMergeCand + mergeCandIbcGpm] = distParamSad.distFunc(distParamSad);
+      }
+#endif
+
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_GPM
+      updateCandList(ModeIbcInfo(mergeCand+mergeCtx.numValidMergeCand, false, 0, false, 0, 0, 0, 0, 0), cost, rdModeList, candCostList, numMrgSATDCand);
+#else
+      updateCandList(ModeIbcInfo(mergeCand+mergeCtx.numValidMergeCand, false, 0), cost, rdModeList, candCostList, numMrgSATDCand);
+#endif
+#else
+#if JVET_AC0112_IBC_GPM
+      updateCandList(ModeIbcInfo(mergeCand+mergeCtx.numValidMergeCand, false, 0, 0, 0, 0, 0), cost, rdModeList, candCostList, numMrgSATDCand);
+#else
       updateCandList(mergeCand+mergeCtx.numValidMergeCand, cost, rdModeList, candCostList, numMrgSATDCand);
+#endif
+#endif
     }
 #endif
+#if JVET_AC0112_IBC_GPM
+    if (testIbcGpm && mergeCtxTm.numValidMergeCand > 0)
+    {
+      mergeCtxTmIbcGeo = mergeCtxTm;
+#if JVET_AA0070_RRIBC
+      m_pcInterSearch->adjustIbcMergeRribcCand(pu, mergeCtxTmIbcGeo, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+#endif
+      for (int i = 0; i < skipCandNumTm[mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand - 1]; i++)
+      {
+        isSkipThisCand[mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand - 1 - i] = true;
+      }
+    }
+#endif
+
 #if JVET_AA0061_IBC_MBVD
 #if JVET_AA0070_RRIBC
     int numValidBvIBC = mergeCtxTmp.numValidMergeCand;
@@ -11268,16 +11756,109 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
           {
             m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipV, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
           }
+#endif
+#if JVET_AC0112_IBC_LIC
+          if (pu.cu->ibcLicFlag)
+          {
+            Pel* piPred = predBuf.buf;
+            int predStride = predBuf.stride;
+            int height = predBuf.height;
+            int width = predBuf.width;
+            for (int h = 0; h < height; h++)
+            {
+              memcpy(piPred, piRefSrch + h * refStride + refStride * yPred + xPred, width * sizeof(Pel));
+              piPred += predStride;
+            }
+            m_pcInterSearch->xLocalIlluComp(pu, COMPONENT_Y, pu.bv, predBuf);
+            distParam.cur = predBuf;
+          }
+          else
 #endif
           distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
 
           Distortion sad = distParam.distFunc(distParam);
           uint32_t bitsCand = PU::getIbcMbvdEstBits(pu, mmvdMergeCandtemp);
+#if JVET_AC0112_IBC_CIIP
+          uint32_t ibcMbvdBits = bitsCand;
+#endif
           bitsCand++; // for ibc_mbvd_flag
           double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
+
+#if JVET_AC0112_IBC_CIIP
+          if (testIbcCiip)
+          {
+            const PredictionUnit *puBv = pu.cs->getPURestricted(pu.lumaPos().offset(xPred, yPred), pu, pu.chType);
+            int intraDir = puBv ? puBv->getIpmInfo(pu.lumaPos().offset(xPred, yPred)) : PLANAR_IDX;
+            if (intraDir != ibcCiipIntraList[0])
+            {
+              ibcCiipIntraList[1] = intraDir;
+            }
+            else
+            {
+              ibcCiipIntraList[1] = ibcCiipIntraList[0] == PLANAR_IDX ? HOR_IDX : PLANAR_IDX;
+            }
+            intraDir = ibcCiipIntraList[1];
+            if (!intraPredBufSet[intraDir])
+            {
+              pu.ibcCiipFlag = true;
+              pu.intraDir[0] = intraDir;
+              intraPredBufSet[intraDir] = true;
+              intraPredBuf[intraDir] = m_acMergeBuffer[intraDir + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+              m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+              m_pcIntraSearch->predIntraAng(COMPONENT_Y, intraPredBuf[intraDir].Y(), pu);
+              pu.ibcCiipFlag = false;
+            }
+            for (int dirIdx = 0; dirIdx < IBC_CIIP_MAX_NUM_INTRA_CANDS; dirIdx++)
+            {
+              int height = pu.lheight();
+              int width = pu.lwidth();
+              const Pel *pPredIbc = piRefSrch + refStride * yPred + xPred;
+              Pel *pPredDst = ibcCiipBuf.buf;
+              int dstStride = ibcCiipBuf.stride;
+              Pel *pPredIntra = intraPredBuf[ibcCiipIntraList[dirIdx]].Y().buf;
+              int intraStride = intraPredBuf[ibcCiipIntraList[dirIdx]].Y().stride;
+              m_pcIntraSearch->m_ibcCiipBlending(pPredDst, dstStride, pPredIbc, refStride, pPredIntra, intraStride, wIbc, wIntra, shift, width, height);
+
+              distParam.cur.buf = ibcCiipBuf.buf;
+              distParam.cur.stride = ibcCiipBuf.stride;
+
+              Distortion sad2 = distParam.distFunc(distParam);
+              uint32_t bitsCand2 = ibcMbvdBits;
+              bitsCand2++; // for ibc_mbvd_flag
+              bitsCand2 += dirIdx + 1;
+              if (dirIdx == IBC_CIIP_MAX_NUM_INTRA_CANDS - 1)
+              {
+                bitsCand2--;
+              }
+              double cost2 = (double)sad2 + (double)bitsCand2 * sqrtLambdaForFirstPass;
+              if (cost2 < ibcCiipBestSatdCost)
+              {
+                ibcCiipBestMergeCand = mmvdMergeCandtemp + mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand;
+                ibcCiipBestIntraCand = dirIdx;
+                ibcCiipBestSatdCost = cost2;
+              }
+            }
+          }
+#endif
+
 #if JVET_Z0084_IBC_TM
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_GPM
+          updateCandList(ModeIbcInfo(mmvdMergeCandtemp + mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand, false, 0, false, 0, 0, 0, 0, 0), cost, rdModeList, candCostList
+            , numMrgSATDCand);
+#else
+          updateCandList(ModeIbcInfo(mmvdMergeCandtemp + mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand, false, 0), cost, rdModeList, candCostList
+            , numMrgSATDCand);
+#endif
+#else
+#if JVET_AC0112_IBC_GPM
+          updateCandList(ModeIbcInfo(mmvdMergeCandtemp + mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand, false, 0, 0, 0, 0, 0), cost, rdModeList, candCostList
+            , numMrgSATDCand);
+#else
           updateCandList(mmvdMergeCandtemp + mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand, cost, rdModeList, candCostList
             , numMrgSATDCand);
+#endif
+#endif
 #else
           updateCandList(mmvdMergeCandtemp + mergeCtx.numValidMergeCand, cost, rdModeList, candCostList
             , numMrgSATDCand);
@@ -11291,30 +11872,310 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     m_tmpStorageCUflipV.destroy();
 #endif
 
-      // Try to limit number of candidates using SATD-costs
-      if (numValidBv)
+#if JVET_AC0112_IBC_GPM
+      static_vector<int, IBC_GPM_MAX_TRY_WEIGHTED_SATD> geoSplitDirList;
+      static_vector<int, IBC_GPM_MAX_TRY_WEIGHTED_SATD> geoMergeCand0;
+      static_vector<int, IBC_GPM_MAX_TRY_WEIGHTED_SATD> geoMergeCand1;
+      static_vector<uint8_t, IBC_GPM_MAX_TRY_WEIGHTED_SATD>  geoBldIdxList;
+      static_vector<double, IBC_GPM_MAX_TRY_WEIGHTED_SATD> geoSADCostList;
+      int numSATDCands = IBC_GPM_MAX_TRY_WEIGHTED_SATD;
+      double ibcGpmBestSatdCost = MAX_DOUBLE;
+      int bestCandidateIdx = 0;
+      int m_numIbcCandPerPar = 6;
+      if (testIbcGpm && ibcGpmCandNumValid > 0)
       {
-#if JVET_AA0061_IBC_MBVD
-        numMrgSATDCand = std::min(numMrgSATDCand,numValidBv);
-        for (int i = 1; i < numMrgSATDCand; i++)
-#else
-        numMrgSATDCand = numValidBv;
-        for (unsigned int i = 1; i < numValidBv; i++)
-#endif
+        int bitsCandSplit = floorLog2(IBC_GPM_MAX_SPLIT_DIR_SECOND_SET_NUM) + 1;
+
+        int wIdx = floorLog2(cu.lwidth()) - GEO_MIN_CU_LOG2;
+        int hIdx = floorLog2(cu.lheight()) - GEO_MIN_CU_LOG2;
+        for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
         {
-          if (candCostList[i] > MRG_FAST_RATIO*candCostList[0])
+          if (!g_ibcGpmSecondSetSplitDir[splitDir] && g_GeoParams[splitDir][0] % 8 != 0)
           {
-            numMrgSATDCand = i;
-            break;
+            continue;
           }
-        }
-      }
-      else
-      {
-        tempCS->dist = 0;
-        tempCS->fracBits = 0;
-        tempCS->cost = MAX_DOUBLE;
-        tempCS->costDbOffset = 0;
+          int maskStride = 0, maskStride2 = 0;
+          int stepX = 1;
+          Pel* SADmask;
+          int16_t angle = g_GeoParams[splitDir][0];
+          if (g_angle2mirror[angle] == 2)
+          {
+            maskStride = -GEO_WEIGHT_MASK_SIZE;
+            maskStride2 = -(int)cu.lwidth();
+            SADmask = &g_globalGeoEncSADmask[g_angle2mask[g_GeoParams[splitDir][0]]][(GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][1]) * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+          }
+          else if (g_angle2mirror[angle] == 1)
+          {
+            stepX = -1;
+            maskStride2 = cu.lwidth();
+            maskStride = GEO_WEIGHT_MASK_SIZE;
+            SADmask = &g_globalGeoEncSADmask[g_angle2mask[g_GeoParams[splitDir][0]]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + (GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][0])];
+          }
+          else
+          {
+            maskStride = GEO_WEIGHT_MASK_SIZE;
+            maskStride2 = -(int)cu.lwidth();
+            SADmask = &g_globalGeoEncSADmask[g_angle2mask[g_GeoParams[splitDir][0]]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+          }
+          Distortion sadSmall = 0, sadLarge = 0;
+          double tempCost = 0;
+#if JVET_AA0070_RRIBC
+          m_pcRdCost->setDistParam(distParam, tmpOrgLuma, refBuf.buf, refBuf.stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+#else
+        if (tempCS->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
+        {
+          const CompArea &area = cu.blocks[COMPONENT_Y];
+          CompArea    tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
+          PelBuf tmpLuma = m_tmpStorageLCU->getBuf(tmpArea);
+          tmpLuma.rspSignal( tempCS->getOrgBuf().Y(), m_pcReshape->getFwdLUT() );
+          m_pcRdCost->setDistParam(distParam, tmpLuma, refBuf.buf, refBuf.stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+        }
+        else
+        {
+          m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), refBuf.buf, refBuf.stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+        }
+#endif
+          for (unsigned int mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; mergeCand++)
+          {
+            if (isSkipThisCand[mergeCand])
+            {
+              continue;
+            }
+            distParam.cur = ibcPredBuf[mergeCand].Y();
+            sadLarge = distParam.distFunc(distParam);
+            tempCost = (double)sadLarge;
+            m_geoMMVDCostList.insert(splitDir, 0, mergeCand, 0, tempCost);
+            sortCandList(tempCost, mergeCand, sadCostList0[splitDir], mergeCandList0[splitDir], m_numIbcCandPerPar);
+            sadSmall = sadWholeBlk[mergeCand] - sadLarge;
+            tempCost = (double)sadSmall;
+            m_geoMMVDCostList.insert(splitDir, 1, mergeCand, 0, tempCost);
+            sortCandList(tempCost, mergeCand, sadCostList1[splitDir], mergeCandList1[splitDir], m_numIbcCandPerPar);
+          }
+#if JVET_Z0084_IBC_TM && IBC_TM_MRG
+          for (unsigned int mergeCand = 0; mergeCand < mergeCtxTm.numValidMergeCand; mergeCand++)
+          {
+            if (isSkipThisCand[mergeCtx.numValidMergeCand + mergeCand])
+            {
+              continue;
+            }
+            distParam.cur = ibcPredBuf[mergeCtx.numValidMergeCand + mergeCand].Y();
+            sadLarge = distParam.distFunc(distParam);
+            tempCost = (double)sadLarge;
+            m_geoMMVDCostList.insert(splitDir, 0, mergeCtx.numValidMergeCand + mergeCand, 0, tempCost);
+            sortCandList(tempCost, mergeCtx.numValidMergeCand + mergeCand, sadCostList0[splitDir], mergeCandList0[splitDir], m_numIbcCandPerPar);
+            sadSmall = sadWholeBlk[mergeCtx.numValidMergeCand + mergeCand] - sadLarge;
+            tempCost = (double)sadSmall;
+            m_geoMMVDCostList.insert(splitDir, 1, mergeCtx.numValidMergeCand + mergeCand, 0, tempCost);
+            sortCandList(tempCost, mergeCtx.numValidMergeCand + mergeCand, sadCostList1[splitDir], mergeCandList1[splitDir], m_numIbcCandPerPar);
+          }
+#endif
+          for (unsigned int mergeCand = IBC_GPM_MAX_NUM_UNI_CANDS; mergeCand < IBC_GPM_MAX_NUM_UNI_CANDS + IBC_GPM_MAX_NUM_INTRA_CANDS; mergeCand++)
+          {
+            int intraIdx = mergeCand - IBC_GPM_MAX_NUM_UNI_CANDS;
+            int rdobuffer = ibcGpmIntraCandList[splitDir][0][intraIdx];
+            distParam.cur =  intraPredBuf[rdobuffer].Y();
+            sadLarge = distParam.distFunc(distParam);
+            tempCost = (double)sadLarge;
+            m_geoMMVDCostList.insert(splitDir, 0, mergeCand, 0, tempCost);
+            sortIntraCandList(tempCost, mergeCand, intraSadCostList0[splitDir], intraCandList0[splitDir]);
+
+            if (ibcGpmIntraCandList[splitDir][0][intraIdx] != ibcGpmIntraCandList[splitDir][1][intraIdx])
+            {
+              rdobuffer = ibcGpmIntraCandList[splitDir][1][intraIdx];
+              distParam.cur = intraPredBuf[rdobuffer].Y();
+              sadLarge = distParam.distFunc(distParam);
+            }
+            sadSmall = sadIntraWholeBlk[rdobuffer] - sadLarge;
+            tempCost = (double)sadSmall;
+            m_geoMMVDCostList.insert(splitDir, 1, mergeCand, 0, tempCost);
+            sortIntraCandList(tempCost, mergeCand, intraSadCostList1[splitDir], intraCandList1[splitDir]);
+          }
+        }
+        for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
+        {
+          if (!g_ibcGpmSecondSetSplitDir[splitDir] && g_GeoParams[splitDir][0] % 8 != 0)
+          {
+            continue;
+          }
+          int numCandMerge0 = min(m_numIbcCandPerPar, (int)mergeCandList0[splitDir].size());
+          int numCandIntra0 = (int)intraCandList0[splitDir].size();
+          int numCandPart0 = numCandMerge0 + numCandIntra0;
+          for (int candIdx0 = 0; candIdx0 < numCandPart0; candIdx0++)
+          {
+            int mergeCand0 = candIdx0 < numCandMerge0 ? mergeCandList0[splitDir][candIdx0] : intraCandList0[splitDir][candIdx0-numCandMerge0];
+            int numCandMerge1 = min(m_numIbcCandPerPar, (int)mergeCandList1[splitDir].size());
+            int numCandIntra1 = candIdx0 < numCandMerge0 ? (int)intraCandList1[splitDir].size() : 0;
+            int numCandPart1 = numCandMerge1 + numCandIntra1;
+            int candStart1 = 0;
+            for (int candIdx1 = candStart1; candIdx1 < numCandPart1; candIdx1++)
+            {
+              int mergeCand1 = candIdx1 < numCandMerge1 ? mergeCandList1[splitDir][candIdx1] : intraCandList1[splitDir][candIdx1-numCandMerge1];
+              if (mergeCand0 == mergeCand1)
+              {
+                continue;
+              }
+              if ((candIdx0 < numCandMerge0 && candIdx1 < numCandMerge1) || (candIdx0 >= numCandMerge0 && candIdx1 >= numCandMerge1))
+              {
+                continue;
+              }
+              if (isSkipThisCand[mergeCand0] || isSkipThisCand[mergeCand1])
+              {
+                continue;
+              }
+              double tempCost = m_geoMMVDCostList.singleDistList[0][splitDir][mergeCand0][0].cost + m_geoMMVDCostList.singleDistList[1][splitDir][mergeCand1][0].cost;
+              updateGeoIbcCandList(tempCost, splitDir, mergeCand0, mergeCand1, 0, 0, geoSADCostList, geoSplitDirList, geoMergeCand0, geoMergeCand1, numSATDCands);
+            }
+          }
+        }
+
+#if JVET_AA0070_RRIBC
+        m_pcRdCost->setDistParam(distParam, tmpOrgLuma, m_acMergeBuffer[0].Y(), sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+#else
+        if (tempCS->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
+        {
+          const CompArea &area = cu.blocks[COMPONENT_Y];
+          CompArea    tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
+          PelBuf tmpLuma = m_tmpStorageLCU->getBuf(tmpArea);
+          tmpLuma.rspSignal( tempCS->getOrgBuf().Y(), m_pcReshape->getFwdLUT() );
+          m_pcRdCost->setDistParam(distParam, tmpLuma, m_acMergeBuffer[0].Y(), sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+        }
+        else
+        {
+          m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+        }
+#endif
+        int numberGeoCandChecked = (int)geoSADCostList.size();
+        for (uint8_t bldIdx = 0; bldIdx < IBC_GPM_NUM_BLENDING; bldIdx++)
+        {
+          for (uint8_t candidateIdx = 0; candidateIdx < numberGeoCandChecked; candidateIdx++)
+          {
+            int splitDir = geoSplitDirList[candidateIdx];
+            int mergeCand0 = geoMergeCand0[candidateIdx];
+            int mergeCand1 = geoMergeCand1[candidateIdx];
+            geoCombinations[candidateIdx * IBC_GPM_NUM_BLENDING + bldIdx] = m_acGeoWeightedBuffer[candidateIdx * IBC_GPM_NUM_BLENDING + bldIdx].getBuf(localUnitArea);
+            int isIntra0 = (mergeCand0 >= IBC_GPM_MAX_NUM_UNI_CANDS) ? 1 : 0;
+            int isIntra1 = (mergeCand1 >= IBC_GPM_MAX_NUM_UNI_CANDS) ? 1 : 0;
+            int bitsCand = 1 + (g_GeoParams[splitDir][0] % 8 == 0 ? 4 : bitsCandSplit);
+            if (IBC_GPM_NUM_BLENDING > 1)
+            {
+              bitsCand++;
+              if (bldIdx > 0)
+              {
+                bitsCand += 2;
+              }
+            }
+            {
+              PelUnitBuf predSrc0, predSrc1;
+              if (isIntra0)
+              {
+                int intraIdx0 = mergeCand0 - IBC_GPM_MAX_NUM_UNI_CANDS;
+                int rdoBuffer = ibcGpmIntraCandList[splitDir][0][intraIdx0];
+                predSrc0 = intraPredBuf[rdoBuffer];
+                bitsCand += intraIdx0 + 1;
+                if (intraIdx0 == IBC_GPM_MAX_NUM_INTRA_CANDS - 1)
+                {
+                  bitsCand--;
+                }
+              }
+              else
+              {
+                predSrc0 = ibcPredBuf[mergeCand0];
+                int tempMergeCand0 = mergeCand0 > mergeCtx.numValidMergeCand ? mergeCand0 - mergeCtx.numValidMergeCand : mergeCand0;
+                bitsCand += tempMergeCand0 + 1;
+                if (tempMergeCand0 == tempCS->sps->getMaxNumIBCMergeCand() - 1)
+                {
+                  bitsCand--;
+                }
+              }
+              if (isIntra1)
+              {
+                int intraIdx1 = mergeCand1 - IBC_GPM_MAX_NUM_UNI_CANDS;
+                int rdoBuffer = ibcGpmIntraCandList[splitDir][1][intraIdx1];
+                predSrc1 = intraPredBuf[rdoBuffer];
+                bitsCand += intraIdx1 + 1;
+                if (intraIdx1 == IBC_GPM_MAX_NUM_INTRA_CANDS - 1)
+                {
+                  bitsCand--;
+                }
+              }
+              else
+              {
+                predSrc1 = ibcPredBuf[mergeCand1];
+                int tempMergeCand1 = mergeCand1 > mergeCtx.numValidMergeCand ? mergeCand1 - mergeCtx.numValidMergeCand : mergeCand1;
+                bitsCand += tempMergeCand1 + 1;
+                if (tempMergeCand1 == tempCS->sps->getMaxNumIBCMergeCand() - 1)
+                {
+                  bitsCand--;
+                }
+              }
+              m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, bldIdx, CHANNEL_TYPE_LUMA, geoCombinations[candidateIdx*IBC_GPM_NUM_BLENDING+bldIdx], predSrc0, predSrc1);
+            }
+            distParam.cur = geoCombinations[candidateIdx * IBC_GPM_NUM_BLENDING + bldIdx].Y();
+            Distortion sad = distParam.distFunc(distParam);
+            double updateCost = (double)sad;
+            updateCost += bitsCand * sqrtLambdaForFirstPass;
+            if (updateCost < ibcGpmBestSatdCost)
+            {
+              bestCandidateIdx = candidateIdx * IBC_GPM_NUM_BLENDING + bldIdx;
+              ibcGpmBestSatdCost = updateCost;
+            }
+          }
+        }
+      }
+#endif
+
+      // Try to limit number of candidates using SATD-costs
+      if (numValidBv)
+      {
+#if JVET_AA0061_IBC_MBVD
+        numMrgSATDCand = std::min(numMrgSATDCand,numValidBv);
+        for (int i = 1; i < numMrgSATDCand; i++)
+#else
+        numMrgSATDCand = numValidBv;
+        for (unsigned int i = 1; i < numValidBv; i++)
+#endif
+        {
+          if (candCostList[i] > MRG_FAST_RATIO*candCostList[0])
+          {
+            numMrgSATDCand = i;
+            break;
+          }
+        }
+
+#if JVET_AC0112_IBC_CIIP
+        if (testIbcCiip && ibcCiipBestSatdCost != MAX_DOUBLE)
+        {
+          if (ibcCiipBestSatdCost < candCostList[candCostList.size() - 1])
+          {
+            rdModeList[numMrgSATDCand].mergeCand = ibcCiipBestMergeCand;
+            rdModeList[numMrgSATDCand].isCIIP = true;
+            rdModeList[numMrgSATDCand].dirIdx = ibcCiipBestIntraCand;
+            numMrgSATDCand++;
+          }
+        }
+#endif
+#if JVET_AC0112_IBC_GPM
+        if (testIbcGpm && ibcGpmBestSatdCost != MAX_DOUBLE && ibcGpmBestSatdCost < candCostList[candCostList.size() - 1])
+        {
+          uint8_t candidateIdx = bestCandidateIdx;
+          int splitDir = geoSplitDirList[candidateIdx/IBC_GPM_NUM_BLENDING];
+          int mergeCand0 = geoMergeCand0[candidateIdx/IBC_GPM_NUM_BLENDING];
+          int mergeCand1 = geoMergeCand1[candidateIdx/IBC_GPM_NUM_BLENDING];
+          int bldIdx = candidateIdx%IBC_GPM_NUM_BLENDING;
+#if JVET_AC0112_IBC_CIIP
+          rdModeList.at(numMrgSATDCand++) = ModeIbcInfo(0, false, 0, true, mergeCand0, mergeCand1, splitDir, bldIdx, candidateIdx);
+#else
+          rdModeList.at(numMrgSATDCand++) = ModeIbcInfo(0, true, mergeCand0, mergeCand1, splitDir, bldIdx, candidateIdx);
+#endif
+        }
+#endif
+      }
+      else
+      {
+        tempCS->dist = 0;
+        tempCS->fracBits = 0;
+        tempCS->cost = MAX_DOUBLE;
+        tempCS->costDbOffset = 0;
         tempCS->initStructData(encTestMode.qp);
         return;
       }
@@ -11331,7 +12192,29 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
   {
     for (unsigned int mrgHADIdx = 0; mrgHADIdx < numMrgSATDCand; mrgHADIdx++)
     {
+#if JVET_AC0112_IBC_CIIP
+      unsigned int mergeCand = rdModeList[mrgHADIdx].mergeCand;
+      if (numResidualPass == 1 && rdModeList[mrgHADIdx].isCIIP)
+      {
+        continue;
+      }
+#if JVET_AC0112_IBC_GPM
+      if (rdModeList[mrgHADIdx].isIbcGpm)
+      {
+        mergeCand = rdModeList[mrgHADIdx].mergeIdx0 < IBC_GPM_MAX_NUM_UNI_CANDS ? rdModeList[mrgHADIdx].mergeIdx0 : rdModeList[mrgHADIdx].mergeIdx1;
+      }
+#endif
+#else
+#if JVET_AC0112_IBC_GPM
+      unsigned int mergeCand = rdModeList[mrgHADIdx].mergeCand;
+      if (rdModeList[mrgHADIdx].isIbcGpm)
+      {
+        mergeCand = rdModeList[mrgHADIdx].mergeIdx0 < IBC_GPM_MAX_NUM_UNI_CANDS ? rdModeList[mrgHADIdx].mergeIdx0 : rdModeList[mrgHADIdx].mergeIdx1;
+      }
+#else
       unsigned int mergeCand = rdModeList[mrgHADIdx];
+#endif
+#endif
       if (!(numResidualPass == 1 && candHasNoResidual[mergeCand] == 1))
       {
         if (!(bestIsSkip && (numResidualPass == 0)))
@@ -11352,6 +12235,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if INTER_LIC
             cu.LICFlag = false;
 #endif
+#if JVET_AC0112_IBC_LIC
+            cu.ibcLicFlag = false;
+#endif
 
 #if JVET_AA0070_RRIBC
             cu.rribcFlipType = 0;
@@ -11359,10 +12245,17 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);// tempCS->addPU(cu);
             pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
             pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
+#if JVET_AC0112_IBC_CIIP
+            pu.ibcCiipFlag = rdModeList[mrgHADIdx].isCIIP;
+            pu.ibcCiipIntraIdx = rdModeList[mrgHADIdx].dirIdx;
+#endif
             cu.mmvdSkip = false;
             pu.mmvdMergeFlag = false;
             pu.regularMergeFlag = false;
             cu.geoFlag = false;
+#if JVET_AC0112_IBC_GPM
+            pu.ibcGpmFlag = rdModeList[mrgHADIdx].isIbcGpm;
+#endif
 #if JVET_AA0061_IBC_MBVD
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
             int numPreviousBv = mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand;
@@ -11384,14 +12277,38 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
               {
                 pu.tmMergeFlag = true;
                 mergeCand -= mergeCtx.numValidMergeCand;
+#if JVET_AC0112_IBC_GPM
+                if (pu.ibcGpmFlag)
+                {
+                  mergeCtxTmIbcGeo.setMergeInfo(pu, mergeCand);
+                  PU::spanMotionInfo(pu, mergeCtxTmIbcGeo);
+                }
+                else
+                {
+#endif
                 mergeCtxTm.setMergeInfo(pu, mergeCand);
                 PU::spanMotionInfo(pu, mergeCtxTm);
+#if JVET_AC0112_IBC_GPM
+                }
+#endif
               }
               else
 #endif
               {
+#if JVET_AC0112_IBC_GPM
+                if (pu.ibcGpmFlag)
+                {
+                  mergeCtxIbcGeo.setMergeInfo(pu, mergeCand);
+                  PU::spanMotionInfo(pu, mergeCtxIbcGeo);
+                }
+                else
+                {
+#endif
                 mergeCtx.setMergeInfo(pu, mergeCand);
                 PU::spanMotionInfo(pu, mergeCtx);
+#if JVET_AC0112_IBC_GPM
+                }
+#endif
               }
 #if JVET_AA0061_IBC_MBVD
             }
@@ -11402,7 +12319,101 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             const bool chroma = !pu.cu->isSepTree();
 #endif
             //  MC
+#if JVET_AC0112_IBC_GPM
+            if (pu.ibcGpmFlag)
+            {
+              int candidateIdx = rdModeList[mrgHADIdx].combIdx;
+              pu.ibcGpmMergeIdx0 = rdModeList[mrgHADIdx].mergeIdx0;
+              pu.ibcGpmMergeIdx1 = rdModeList[mrgHADIdx].mergeIdx1;
+              if (rdModeList[mrgHADIdx].mergeIdx0 < IBC_GPM_MAX_NUM_UNI_CANDS && rdModeList[mrgHADIdx].mergeIdx0 >= mergeCtx.numValidMergeCand)
+              {
+                pu.ibcGpmMergeIdx0 =  pu.ibcGpmMergeIdx0 - mergeCtx.numValidMergeCand;
+              }
+              if (rdModeList[mrgHADIdx].mergeIdx1 < IBC_GPM_MAX_NUM_UNI_CANDS && rdModeList[mrgHADIdx].mergeIdx1 >= mergeCtx.numValidMergeCand)
+              {
+                pu.ibcGpmMergeIdx1 =  pu.ibcGpmMergeIdx1 - mergeCtx.numValidMergeCand;
+              }
+              pu.ibcGpmSplitDir = rdModeList[mrgHADIdx].splitDir;
+              pu.ibcGpmBldIdx = rdModeList[mrgHADIdx].bldIdx;
+              if (chroma)
+              {
+                m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, false, chroma);
+                if (pu.ibcGpmMergeIdx0 >= IBC_GPM_MAX_NUM_UNI_CANDS)
+                {
+                  pu.intraDir[1] = ibcGpmIntraCandList[pu.ibcGpmSplitDir][0][pu.ibcGpmMergeIdx0 - IBC_GPM_MAX_NUM_UNI_CANDS];
+                }
+                else
+                {
+                  pu.intraDir[1] = ibcGpmIntraCandList[pu.ibcGpmSplitDir][1][pu.ibcGpmMergeIdx1 - IBC_GPM_MAX_NUM_UNI_CANDS];
+                }
+                if (!intraPredBufSet[0])
+                {
+                  intraPredBuf[0] = m_acMergeBuffer[0 + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+                  intraPredBufSet[0] = true;
+                }
+                m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb());
+                m_pcIntraSearch->predIntraAng(COMPONENT_Cb, intraPredBuf[0].Cb(), pu);
+                m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr());
+                m_pcIntraSearch->predIntraAng(COMPONENT_Cr, intraPredBuf[0].Cr(), pu);
+                pu.intraDir[1] = PLANAR_IDX;
+                PelUnitBuf predBuf = cu.cs->getPredBuf(pu);
+                if (pu.ibcGpmMergeIdx0 < IBC_GPM_MAX_NUM_UNI_CANDS)
+                {
+                  m_pcInterSearch->weightedGeoBlkRounded(pu, pu.ibcGpmSplitDir, pu.ibcGpmBldIdx, CHANNEL_TYPE_CHROMA, geoCombinations[candidateIdx], predBuf, intraPredBuf[0]);
+                }
+                else
+                {
+                  m_pcInterSearch->weightedGeoBlkRounded(pu, pu.ibcGpmSplitDir, pu.ibcGpmBldIdx, CHANNEL_TYPE_CHROMA, geoCombinations[candidateIdx], intraPredBuf[0], predBuf);
+                }
+              }
+              tempCS->getPredBuf().copyFrom(geoCombinations[candidateIdx]);
+            }
+            else
+#endif
             m_pcInterSearch->motionCompensation(pu,REF_PIC_LIST_0, true, chroma);
+#if JVET_AC0112_IBC_CIIP
+            if (pu.ibcCiipFlag)
+            {
+              if (pu.ibcCiipIntraIdx > 0)
+              {
+                int xPred = pu.bv.getHor();
+                int yPred = pu.bv.getVer();
+                const PredictionUnit *puBv = pu.cs->getPURestricted(pu.lumaPos().offset(xPred, yPred), pu, pu.chType);
+                int intraDir = puBv ? puBv->getIpmInfo(pu.lumaPos().offset(xPred, yPred)) : PLANAR_IDX;
+                if (intraDir != ibcCiipIntraList[0])
+                {
+                  ibcCiipIntraList[1] = intraDir;
+                }
+                else
+                {
+                  ibcCiipIntraList[1] = ibcCiipIntraList[0] == PLANAR_IDX ? HOR_IDX : PLANAR_IDX;
+                }
+                intraDir = ibcCiipIntraList[1];
+                if (!intraPredBufSet[intraDir])
+                {
+                  pu.intraDir[0] = intraDir;
+                  intraPredBufSet[intraDir] = true;
+                  intraPredBuf[intraDir] = m_acMergeBuffer[intraDir + IBC_GPM_MAX_NUM_UNI_CANDS].getBuf(localUnitArea);
+                  m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+                  m_pcIntraSearch->predIntraAng(COMPONENT_Y, intraPredBuf[intraDir].Y(), pu);
+                }
+              }
+              m_pcIntraSearch->geneWeightedPred( COMPONENT_Y, tempCS->getPredBuf(pu).Y(), pu, tempCS->getPredBuf(pu).Y(), intraPredBuf[ibcCiipIntraList[pu.ibcCiipIntraIdx]].Y() );
+
+              if (chroma)
+              {
+                pu.intraDir[1] = ibcCiipIntraList[pu.ibcCiipIntraIdx];
+                m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb());
+                m_pcIntraSearch->predIntraAng(COMPONENT_Cb, intraPredBuf[pu.intraDir[1]].Cb(), pu);
+                m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr());
+                m_pcIntraSearch->predIntraAng(COMPONENT_Cr, intraPredBuf[pu.intraDir[1]].Cr(), pu);
+                m_pcIntraSearch->geneWeightedPred( COMPONENT_Cb, tempCS->getPredBuf(pu).Cb(), pu, tempCS->getPredBuf(pu).Cb(), intraPredBuf[pu.intraDir[1]].Cb() );
+                m_pcIntraSearch->geneWeightedPred( COMPONENT_Cr, tempCS->getPredBuf(pu).Cr(), pu, tempCS->getPredBuf(pu).Cr(), intraPredBuf[pu.intraDir[1]].Cr() );
+              }
+              pu.intraDir[0] = DC_IDX;
+              pu.intraDir[1] = PLANAR_IDX;
+            }
+#endif
             m_CABACEstimator->getCtx() = m_CurrCtx->start;
 
             m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, (numResidualPass != 0), true, chroma);
@@ -11425,6 +12436,13 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             xCheckChromaQPOffset( *tempCS, partitioner );
 
 
+#if JVET_AC0112_IBC_CIIP
+            if((tempCS->getCU(partitioner.chType))->skip && (tempCS->getCU(partitioner.chType))->firstPU->ibcCiipFlag)
+            {
+              tempCS->cost = MAX_DOUBLE;
+              tempCS->costDbOffset = 0;
+            }
+#endif
             DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
             xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
 
@@ -11463,9 +12481,75 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
     return;
   }
 
-    tempCS->initStructData(encTestMode.qp);
+  m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
 
-    m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+  double curBestCost = bestCS->cost;
+  bool searchedByHash[1] = {false};
+  Distortion tempCost[1] = {0};
+  Distortion searchCost[2] = {0, 0};
+#endif
+#if JVET_AC0112_IBC_CIIP
+  const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
+  PelBuf ibcCiipIntraBuf[3];
+  bool skipSecondIbcCiipPass = false;
+  Distortion intraCandCost[2] = {0, 0};
+#endif
+
+#if JVET_AC0112_IBC_LIC
+  bool skipSecondLicPass = false;
+  int licIdxMax = tempCS->slice->getSPS()->getUseIbcLic() && (tempCS->area.lx() > 0 || tempCS->area.ly() > 0) ? 2 : 1;
+  if (tempCS->area.lwidth() * tempCS->area.lheight() < 32 || tempCS->area.lwidth() * tempCS->area.lheight() > 256)
+  {
+    licIdxMax = 1;
+  }
+#endif
+#if JVET_AC0112_IBC_CIIP
+    int ibcCiipLoopNum = (tempCS->sps->getUseIbcCiip() && tempCS->slice->getSliceType() == I_SLICE && (tempCS->area.lwidth() * tempCS->area.lheight() >= 32) && tempCS->area.lwidth() <= 32 && tempCS->area.lheight() <= 32 && (tempCS->area.lx() > 0 || tempCS->area.ly() > 0)) ? 2 : 1;
+#if JVET_AA0070_RRIBC
+    if (isSecondPass && ibcCiipLoopNum > 1)
+    {
+      CodedCUInfo& relatedCU = ((EncModeCtrlMTnoRQT *)m_modeCtrl)->getBlkInfo(partitioner.currArea());
+      if (relatedCU.isRribcCoded)
+      {
+        ibcCiipLoopNum = 1;
+      }
+    }
+#endif
+    for (int ibcCiipIdx = 0; ibcCiipIdx < ibcCiipLoopNum; ibcCiipIdx++)
+    {
+#if JVET_AC0112_IBC_LIC
+      if (ibcCiipIdx > 0)
+      {
+        CodingUnit* preBestCu = bestCS->getCU(partitioner.chType);
+        if (preBestCu && preBestCu->ibcLicFlag)
+        {
+          continue;
+        }
+        licIdxMax = 1;
+      }
+      for (int licIdx = 0; licIdx < licIdxMax; licIdx++)
+      {
+        if (licIdx == 1 && skipSecondLicPass)
+        {
+          continue;
+        }
+#endif
+      if (ibcCiipIdx == 1 && skipSecondIbcCiipPass)
+      {
+        continue;
+      }
+#else
+#if JVET_AC0112_IBC_LIC
+      for (int licIdx = 0; licIdx < licIdxMax; licIdx++)
+      {
+        if (licIdx == 1 && skipSecondLicPass)
+        {
+          continue;
+        }
+#endif
+#endif
+    tempCS->initStructData(encTestMode.qp);
 
     CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType);
 
@@ -11478,6 +12562,9 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
     cu.qp = encTestMode.qp;
     cu.imv = 0;
     cu.sbtInfo = 0;
+#if JVET_AC0112_IBC_LIC
+    cu.ibcLicFlag = licIdx;
+#endif
 
     CU::addPUs(cu);
 
@@ -11486,11 +12573,61 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
     PredictionUnit& pu = *cu.firstPU;
     cu.mmvdSkip = false;
     pu.mmvdMergeFlag = false;
+#if JVET_AC0112_IBC_CIIP
+    pu.ibcCiipFlag = ibcCiipIdx;
+#endif
     pu.regularMergeFlag = false;
 #if INTER_LIC
     cu.LICFlag = false;
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+    if (ibcCiipIdx > 0)
+    {
+      int ibcCiipIntraList[IBC_CIIP_MAX_NUM_INTRA_CANDS] = {PLANAR_IDX, HOR_IDX};
+      IntraPrediction::deriveDimdMode(tempCS->picture->getRecoBuf(tempCS->area.Y()), tempCS->area.Y(), cu);
+      cu.timdMode = m_pcIntraSearch->deriveTimdMode(tempCS->picture->getRecoBuf(cu.Y()), cu.Y(), cu);
+      ibcCiipIntraList[0] = MAP131TO67(cu.timdMode);
+      ibcCiipIntraList[1] = ibcCiipIntraList[0] == HOR_IDX ? PLANAR_IDX : HOR_IDX;
+      m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), true);
+      for (int i = 0; i < IBC_CIIP_MAX_NUM_INTRA_CANDS; i++)
+      {
+        pu.ibcCiipIntraIdx = i;
+        ibcCiipIntraBuf[0] = m_ciipBuffer[i].getBuf(localUnitArea.Y());
+        pu.intraDir[0] = ibcCiipIntraList[i];
+        m_pcIntraSearch->initPredIntraParams(pu, pu.Y(), *pu.cs->sps, 0);
+        m_pcIntraSearch->predIntraAng(COMPONENT_Y, ibcCiipIntraBuf[0], pu);
+        pu.interDir = 1;
+        pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF;
+#if JVET_AA0070_RRIBC
+        pu.cu->rribcFlipType = 0;
+        m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, tempCost, &ibcCiipIntraBuf[0], isSecondPass);
+#else
+        m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, tempCost, &ibcCiipIntraBuf[0]);
+#endif
+        intraCandCost[i] = tempCost[0];
+      }
+      pu.ibcCiipIntraIdx = intraCandCost[0] <= intraCandCost[1] ? 0 : 1;
+      tempCost[0] = intraCandCost[0] <= intraCandCost[1] ? intraCandCost[0] : intraCandCost[1];
+      ibcCiipIntraBuf[0] = m_ciipBuffer[pu.ibcCiipIntraIdx].getBuf(localUnitArea.Y());
+#if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
+      const bool chroma = !(CS::isDualITree(*tempCS));
+#else
+      const bool chroma = !pu.cu->isSepTree();
+#endif
+      if (chroma)
+      {
+        ibcCiipIntraBuf[1] = m_ciipBuffer[0].getBuf(localUnitArea.Cb());
+        ibcCiipIntraBuf[2] = m_ciipBuffer[0].getBuf(localUnitArea.Cr());
+        pu.intraDir[1] = ibcCiipIntraList[pu.ibcCiipIntraIdx];
+        m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb());
+        m_pcIntraSearch->predIntraAng(COMPONENT_Cb, ibcCiipIntraBuf[1], pu);
+        m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr());
+        m_pcIntraSearch->predIntraAng(COMPONENT_Cr, ibcCiipIntraBuf[2], pu);
+      }
+    }
+#endif
+
     pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
     pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
 
@@ -11498,13 +12635,69 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
     pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; // last idx in the list
 #if JVET_AA0070_RRIBC
       pu.cu->rribcFlipType = 0;
+#if JVET_AC0112_IBC_CIIP
+      bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, tempCost, pu.ibcCiipFlag ? &ibcCiipIntraBuf[0] : NULL, isSecondPass, pu.ibcCiipFlag ? NULL : searchedByHash);
+#else
+#if JVET_AC0112_IBC_LIC
+      bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, tempCost, isSecondPass, searchedByHash);
+#else
       bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, isSecondPass);
+#endif
+#endif
+#else
+#if JVET_AC0112_IBC_CIIP
+      bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, tempCost, pu.ibcCiipFlag ? &ibcCiipIntraBuf[0] : NULL, pu.ibcCiipFlag ? NULL : searchedByHash);
+#else
+#if JVET_AC0112_IBC_LIC
+      bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, tempCost, searchedByHash);
 #else
       bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap);
 #endif
+#endif
+#endif
+#if JVET_AC0112_IBC_LIC
+      if (licIdx == 0 && searchedByHash[0])
+      {
+        skipSecondLicPass = true;
+      }
+#endif
+#if JVET_AC0112_IBC_CIIP
+      if (ibcCiipIdx == 0 && searchedByHash[0])
+      {
+        skipSecondIbcCiipPass = true;
+      }
+#endif
 
       if (bValid)
       {
+#if JVET_AC0112_IBC_LIC
+#if JVET_AC0112_IBC_CIIP
+        if (ibcCiipIdx == 0)
+        {
+          searchCost[licIdx] = tempCost[0];
+        }
+#else
+        searchCost[licIdx] = tempCost[0];
+#endif
+        if (licIdx > 0 && searchCost[0] > 0 && searchCost[1] > 1.05 * searchCost[0])
+        {
+          continue;
+        }
+#endif
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_LIC
+        if (licIdx == 0)
+        {
+          searchCost[ibcCiipIdx] = tempCost[0];
+        }
+#else
+        searchCost[ibcCiipIdx] = tempCost[0];
+#endif
+        if (ibcCiipIdx > 0 && searchCost[0] > 0 && searchCost[1] > 1.2 * searchCost[0])
+        {
+          continue;
+        }
+#endif
         PU::spanMotionInfo(pu);
 #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
         const bool chroma = !(CS::isDualITree(*tempCS));
@@ -11513,6 +12706,22 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
 #endif
         //  MC
         m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, true, chroma);
+#if JVET_AC0112_IBC_CIIP
+        if (pu.ibcCiipFlag)
+        {
+          m_pcIntraSearch->geneWeightedPred( COMPONENT_Y, cu.cs->getPredBuf(pu).Y(), pu, cu.cs->getPredBuf(pu).Y(), ibcCiipIntraBuf[0] );
+#if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
+          const bool chroma = !(CS::isDualITree(*tempCS));
+#else
+          const bool chroma = !pu.cu->isSepTree();
+#endif
+          if (chroma)
+          {
+            m_pcIntraSearch->geneWeightedPred( COMPONENT_Cb, cu.cs->getPredBuf(pu).Cb(), pu, cu.cs->getPredBuf(pu).Cb(), ibcCiipIntraBuf[1] );
+            m_pcIntraSearch->geneWeightedPred( COMPONENT_Cr, cu.cs->getPredBuf(pu).Cr(), pu, cu.cs->getPredBuf(pu).Cr(), ibcCiipIntraBuf[2] );
+          }
+        }
+#endif
 
         {
 
@@ -11541,6 +12750,18 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
           {
             xCalDebCost( *tempCS, partitioner );
           }
+#if JVET_AC0112_IBC_CIIP
+          if (ibcCiipIdx == 0 && tempCS->cost > curBestCost * 1.1)
+          {
+            skipSecondIbcCiipPass = true;
+          }
+#endif
+#if JVET_AC0112_IBC_LIC
+          if (licIdx == 0 && tempCS->cost > curBestCost * 1.4)
+          {
+            skipSecondLicPass = true;
+          }
+#endif
 
           DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
           xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
@@ -11554,7 +12775,19 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
         tempCS->fracBits = 0;
         tempCS->cost = MAX_DOUBLE;
         tempCS->costDbOffset = 0;
+#if JVET_AC0112_IBC_CIIP
+        if (ibcCiipIdx == 0)
+        {
+          break;
+        }
+#endif
       }
+#if JVET_AC0112_IBC_LIC
+    }
+#endif
+#if JVET_AC0112_IBC_CIIP
+    }
+#endif
 }
   // check ibc mode in encoder RD
   //////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index b96b0f42ad1fd7678e5346de773be1f7953656ce..a74ba15aa19e4de3607a5a59756fbf7760f12590 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1664,6 +1664,15 @@ void EncLib::xInitSPS( SPS& sps )
   sps.setIBCFlag                            ( m_IBCMode);
 #if JVET_AA0061_IBC_MBVD
   sps.setUseIbcMbvd                         ( m_ibcMbvd );
+#endif
+#if JVET_AC0112_IBC_CIIP
+  sps.setUseIbcCiip                         ( m_ibcCiip );
+#endif
+#if JVET_AC0112_IBC_GPM
+  sps.setUseIbcGpm                          ( m_ibcGpm );
+#endif
+#if JVET_AC0112_IBC_LIC
+  sps.setUseIbcLic                          ( m_ibcLic );
 #endif
   sps.setWrapAroundEnabledFlag                      ( m_wrapAround );
 #if MULTI_HYP_PRED
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 9a542c4d6674c719a409d7a4438cbd675b3c6f57..127109a313a617db0342c96eec6905ca1ced0d3e 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -221,6 +221,9 @@ void InterSearch::destroy()
   }
   m_tmpStorageLCU.destroy();
   m_tmpAffiStorage.destroy();
+#if JVET_AC0112_IBC_CIIP
+  m_ibcCiipBuffer.destroy();
+#endif
 
   if ( m_tmpAffiError != NULL )
   {
@@ -375,6 +378,9 @@ void InterSearch::init( EncCfg*        pcEncCfg,
 #else
   m_tmpAffiDeri[0] = new int[MAX_CU_SIZE * MAX_CU_SIZE];
   m_tmpAffiDeri[1] = new int[MAX_CU_SIZE * MAX_CU_SIZE];
+#endif
+#if JVET_AC0112_IBC_CIIP
+  m_ibcCiipBuffer.create(UnitArea(cform, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
 #endif
   m_pTempPel = new Pel[maxCUWidth*maxCUHeight];
   m_affMVListMaxSize = (pcEncCfg->getIntraPeriod() == (uint32_t)-1) ? AFFINE_ME_LIST_SIZE_LD : AFFINE_ME_LIST_SIZE;
@@ -1606,10 +1612,18 @@ end:
 
 // based on xMotionEstimation
 #if JVET_AA0070_RRIBC
+#if JVET_AC0112_IBC_CIIP
+void InterSearch::xIBCEstimation(PredictionUnit &pu, PelUnitBuf &origBuf, PelBuf &ibcCiipIntraBuf, Mv pcMvPred[3][2], Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY, int numRribcType)
+#else
 void InterSearch::xIBCEstimation(PredictionUnit &pu, PelUnitBuf &origBuf, Mv pcMvPred[3][2], Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY, int numRribcType)
+#endif
+#else
+#if JVET_AC0112_IBC_CIIP
+void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, PelBuf &ibcCiipIntraBuf, Mv *pcMvPred, Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY)
 #else
 void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Mv *pcMvPred, Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY)
 #endif
+#endif
 {
   const int iPicWidth = pu.cs->slice->getPPS()->getPicWidthInLumaSamples();
   const int iPicHeight = pu.cs->slice->getPPS()->getPicHeightInLumaSamples();
@@ -1676,6 +1690,26 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Mv *pc
   }
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+  if (pu.ibcCiipFlag)
+  {
+    const Pel *pelOrig = pcPatternKey->buf;
+    Pel *pelIntra = ibcCiipIntraBuf.buf;
+    int height = ibcCiipIntraBuf.height;
+    int width = ibcCiipIntraBuf.width;
+    for( int y = 0; y < height; y++ )
+    {
+      for( int x = 0; x < width; x++ )
+      {
+        pelIntra[x] = (pelOrig[x] << 1) - pelIntra[x];
+      }
+      pelIntra += ibcCiipIntraBuf.stride;
+      pelOrig += pcPatternKey->stride;
+    }
+    pcPatternKey = (CPelBuf*)&ibcCiipIntraBuf;
+  }
+#endif
+
   m_lumaClpRng = pu.cs->slice->clpRng(COMPONENT_Y);
   Picture* refPic = pu.cu->slice->getPic();
   const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]);
@@ -1698,6 +1732,9 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Mv *pc
   m_pcRdCost->setCostScale(0);
 
   m_cDistParam.useMR = false;
+#if JVET_AC0112_IBC_LIC
+  m_cDistParam.useMR = pu.cu->ibcLicFlag;
+#endif
 #if !JVET_AA0070_RRIBC
   m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
 #endif
@@ -2090,10 +2127,26 @@ void InterSearch::xSetIntraSearchRange(PredictionUnit& pu, int iRoiWidth, int iR
 }
 
 #if JVET_AA0070_RRIBC
+#if JVET_AC0112_IBC_CIIP
+bool InterSearch::predIBCSearch( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost, PelBuf* ibcCiipIntraBuf, bool isSecondPass, bool* searchedByHash)
+#else
+#if JVET_AC0112_IBC_LIC
+bool InterSearch::predIBCSearch( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost, bool isSecondPass, bool* searchedByHash)
+#else
 bool InterSearch::predIBCSearch( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, bool isSecondPass)
+#endif
+#endif
+#else
+#if JVET_AC0112_IBC_CIIP
+bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost, PelBuf* ibcCiipIntraBuf, bool* searchedByHash)
+#else
+#if JVET_AC0112_IBC_LIC
+bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost, bool* searchedByHash)
 #else
 bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap)
 #endif
+#endif
+#endif
 {
   Mv           cMvSrchRngLT;
   Mv           cMvSrchRngRB;
@@ -2106,6 +2159,12 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
 #endif
 #if JVET_AA0070_RRIBC
   CodedCUInfo& relatedCU = ((EncModeCtrlMTnoRQT *)m_modeCtrl)->getBlkInfo(partitioner.currArea());
+#if JVET_AC0112_IBC_LIC
+  if (isSecondPass && relatedCU.isRribcCoded && cu.ibcLicFlag)
+  {
+    return false;
+  }
+#endif
 #endif
 
   for (auto &pu : CU::traversePUs(cu))
@@ -2122,6 +2181,18 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
         numRribcType = 1;
       }
     }
+#if JVET_AC0112_IBC_CIIP
+    if (pu.ibcCiipFlag)
+    {
+      numRribcType = 1;
+    }
+#endif
+#if JVET_AC0112_IBC_LIC
+    if (pu.cu->ibcLicFlag)
+    {
+      numRribcType = 1;
+    }
+#endif
     Mv       cMv;
     cMv.setZero();
     int iBvpNum    = 2;
@@ -2137,19 +2208,63 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
 
       // prepare imv = 2 accuracy predictor info
       pu.cu->imv      = 2;
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_LIC
+      if (!pu.ibcCiipFlag && !pu.cu->ibcLicFlag)
+      {
+#else
+      if (!pu.ibcCiipFlag)
+      {
+#endif
+#else
+#if JVET_AC0112_IBC_LIC
+      if (!pu.cu->ibcLicFlag)
+      {
+#endif
+#endif
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
       PU::fillIBCMvpCand(pu, amvpInfo4Pel[i], this);
 #else
       PU::fillIBCMvpCand(pu, amvpInfo4Pel[i]);
 #endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+      m_amvpInfo4Pel[i] = amvpInfo4Pel[i];
+      }
+      else
+      {
+        amvpInfo4Pel[i] = m_amvpInfo4Pel[i];
+      }
+#endif
 
       // prepare imv = 0 accuracy predictor info
       pu.cu->imv = 0;
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_LIC
+      if (!pu.ibcCiipFlag && !pu.cu->ibcLicFlag)
+      {
+#else
+      if (!pu.ibcCiipFlag)
+      {
+#endif
+#else
+#if JVET_AC0112_IBC_LIC
+      if (!pu.cu->ibcLicFlag)
+      {
+#endif
+#endif
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
       PU::fillIBCMvpCand(pu, amvpInfo[i], this);
 #else
       PU::fillIBCMvpCand(pu, amvpInfo[i]);
 #endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+      m_amvpInfo[i] = amvpInfo[i];
+      }
+      else
+      {
+        amvpInfo[i] = m_amvpInfo[i];
+      }
+#endif
 
       // store in full pel accuracy, shift before use in search
       cMvPred[i][0] = amvpInfo[i].mvCand[0];
@@ -2168,20 +2283,64 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
     /// ibc search
     pu.cu->imv = 2;
     AMVPInfo amvpInfo4Pel;
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_LIC
+    if (!pu.ibcCiipFlag && !pu.cu->ibcLicFlag)
+    {
+#else
+    if (!pu.ibcCiipFlag)
+    {
+#endif
+#else
+#if JVET_AC0112_IBC_LIC
+    if (!pu.cu->ibcLicFlag)
+    {
+#endif
+#endif
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
     PU::fillIBCMvpCand(pu, amvpInfo4Pel, this);
 #else
     PU::fillIBCMvpCand(pu, amvpInfo4Pel);
 #endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+      m_amvpInfo4Pel = amvpInfo4Pel;
+    }
+    else
+    {
+      amvpInfo4Pel = m_amvpInfo4Pel;
+    }
+#endif
 
     pu.cu->imv = 0;// (Int)cu.cs->sps->getUseIMV(); // set as IMV=0 initially
     Mv    cMv, cMvPred[2];
     AMVPInfo amvpInfo;
+#if JVET_AC0112_IBC_CIIP
+#if JVET_AC0112_IBC_LIC
+    if (!pu.ibcCiipFlag && !pu.cu->ibcLicFlag)
+    {
+#else
+    if (!pu.ibcCiipFlag)
+    {
+#endif
+#else
+#if JVET_AC0112_IBC_LIC
+    if (!pu.cu->ibcLicFlag)
+    {
+#endif
+#endif
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
     PU::fillIBCMvpCand(pu, amvpInfo, this);
 #else
     PU::fillIBCMvpCand(pu, amvpInfo);
 #endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+      m_amvpInfo = amvpInfo;
+    }
+    else
+    {
+      amvpInfo = m_amvpInfo;
+    }
+#endif
 
     // store in full pel accuracy, shift before use in search
     cMvPred[0] = amvpInfo.mvCand[0];
@@ -2200,23 +2359,57 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
     }
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+    const CompArea &area = pu.blocks[COMPONENT_Y];
+    const UnitArea localUnitArea(area.chromaFormat, Area(0, 0, area.width, area.height));
+    PelBuf ibcCiipIntraBuff = m_ibcCiipBuffer.getBuf(localUnitArea.Y());
+    if (pu.ibcCiipFlag)
+    {
+      ibcCiipIntraBuff.copyFrom(*ibcCiipIntraBuf);
+    }
+#endif
+
+#if JVET_AC0112_IBC_CIIP
+    if (m_pcEncCfg->getIBCHashSearch() && !pu.ibcCiipFlag)
+#else
     if (m_pcEncCfg->getIBCHashSearch())
+#endif
     {
 #if JVET_AA0070_RRIBC
       xxIBCHashSearch(pu, cMvPred, iBvpNum, cMv, bvpIdxBest, ibcHashMap, amvpInfo4Pel, numRribcType);
 #else
       xxIBCHashSearch(pu, cMvPred, iBvpNum, cMv, bvpIdxBest, ibcHashMap);
+#endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+      if (searchedByHash)
+      {
+        *searchedByHash = true;
+      }
 #endif
     }
 
     if (cMv.getHor() == 0 && cMv.getVer() == 0)
     {
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+      if (searchedByHash)
+      {
+        *searchedByHash = false;
+      }
+#endif
       // if hash search does not work or is not enabled
       PelUnitBuf origBuf = pu.cs->getOrgBuf(pu);
 #if JVET_AA0070_RRIBC
+#if JVET_AC0112_IBC_CIIP
+      xIBCEstimation(pu, origBuf, ibcCiipIntraBuff, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY, numRribcType);
+#else
       xIBCEstimation(pu, origBuf, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY, numRribcType);
+#endif
+#else
+#if JVET_AC0112_IBC_CIIP
+      xIBCEstimation(pu, origBuf, ibcCiipIntraBuff, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY);
 #else
       xIBCEstimation(pu, origBuf, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY);
+#endif
 #endif
     }
 
@@ -2226,6 +2419,12 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
     }
     /// ibc search
     /////////////////////////////////////////////////////////
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+    if (bvSearchCost)
+    {
+      *bvSearchCost = cost;
+    }
+#endif
 #if JVET_Z0131_IBC_BVD_BINARIZATION
     m_pcRdCost->setPredictors(cMvPred);
     m_pcRdCost->setCostScale(0);
diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h
index 59e5d4f7cbb32300f5ddbdfe2ea6fd3cf28b53ce..bcb590c276cd1c0524c3e0aea0b0eb4c049f63ad 100644
--- a/source/Lib/EncoderLib/InterSearch.h
+++ b/source/Lib/EncoderLib/InterSearch.h
@@ -248,6 +248,84 @@ struct ModeInfo
 };
 #endif
 
+#if JVET_AC0112_IBC_CIIP
+struct ModeIbcInfo
+{
+#if JVET_AC0112_IBC_GPM
+  uint32_t mergeCand;
+  bool     isCIIP;
+  int      dirIdx;
+  bool     isIbcGpm;
+  int      mergeIdx0;
+  int      mergeIdx1;
+  int      splitDir;
+  int      bldIdx;
+  int      combIdx;
+  ModeIbcInfo() : mergeCand(0), isCIIP(false), dirIdx(0), isIbcGpm(false), mergeIdx0(0), mergeIdx1(0), splitDir(0), bldIdx(0), combIdx(0)
+  {}
+  ModeIbcInfo(const uint32_t mergeCand, const bool isCIIP, const int dirIdx, const bool isIbcGpm, const int mergeIdx0, const int mergeIdx1, const int splitDir, const int bldIdx, const int combIdx
+  ) :
+    mergeCand(mergeCand), isCIIP(isCIIP), dirIdx(dirIdx), isIbcGpm(isIbcGpm), mergeIdx0(mergeIdx0), mergeIdx1(mergeIdx1), splitDir(splitDir), bldIdx(bldIdx), combIdx(combIdx)
+  {}
+  ModeIbcInfo(const CodingUnit cu, const PredictionUnit pu)
+  {
+    mergeCand = pu.mergeIdx;
+    isCIIP = pu.ibcCiipFlag;
+    dirIdx = pu.ibcCiipIntraIdx;
+    isIbcGpm = pu.ibcGpmFlag;
+    mergeIdx0 = pu.ibcGpmMergeIdx0;
+    mergeIdx1 = pu.ibcGpmMergeIdx1;
+    splitDir = pu.ibcGpmSplitDir;
+    bldIdx = pu.ibcGpmBldIdx;
+  }
+#else
+  uint32_t mergeCand;
+  bool     isCIIP;
+  int      dirIdx;
+  ModeIbcInfo() : mergeCand(0), isCIIP(false), dirIdx(0)
+  {}
+  ModeIbcInfo(const uint32_t mergeCand, const bool isCIIP, const int dirIdx
+  ) :
+    mergeCand(mergeCand), isCIIP(isCIIP), dirIdx(dirIdx)
+  {}
+  ModeIbcInfo(const CodingUnit cu, const PredictionUnit pu)
+  {
+    mergeCand = pu.mergeIdx;
+    isCIIP = pu.ibcCiipFlag;
+    dirIdx = pu.ibcCiipIntraIdx;
+  }
+#endif
+};
+#endif
+
+#if JVET_AC0112_IBC_GPM && !JVET_AC0112_IBC_CIIP
+struct ModeIbcInfo
+{
+  uint32_t mergeCand;
+  bool     isIbcGpm;
+  int      mergeIdx0;
+  int      mergeIdx1;
+  int      splitDir;
+  int      bldIdx;
+  int      combIdx;
+  ModeIbcInfo() : mergeCand(0), isIbcGpm(false), mergeIdx0(0), mergeIdx1(0), splitDir(0), bldIdx(0), combIdx(0)
+  {}
+  ModeIbcInfo(const uint32_t mergeCand, const bool isIbcGpm, const int mergeIdx0, const int mergeIdx1, const int splitDir, const int bldIdx, const int combIdx
+  ) :
+    mergeCand(mergeCand), isIbcGpm(isIbcGpm), mergeIdx0(mergeIdx0), mergeIdx1(mergeIdx1), splitDir(splitDir), bldIdx(bldIdx), combIdx(combIdx)
+  {}
+  ModeIbcInfo(const CodingUnit cu, const PredictionUnit pu)
+  {
+    mergeCand = pu.mergeIdx;
+    isIbcGpm = pu.ibcGpmFlag;
+    mergeIdx0 = pu.ibcGpmMergeIdx0;
+    mergeIdx1 = pu.ibcGpmMergeIdx1;
+    splitDir = pu.ibcGpmSplitDir;
+    bldIdx = pu.ibcGpmBldIdx;
+  }
+};
+#endif
+
 #if INTER_LIC
 class EncFastLICCtrl
 {
@@ -307,6 +385,18 @@ private:
 #else
   int*            m_tmpAffiDeri[2];
 #endif
+#if JVET_AC0112_IBC_CIIP
+  PelStorage      m_ibcCiipBuffer;
+#endif
+#if JVET_AC0112_IBC_CIIP || JVET_AC0112_IBC_LIC
+#if JVET_AA0070_RRIBC
+  AMVPInfo        m_amvpInfo[3];
+  AMVPInfo        m_amvpInfo4Pel[3];
+#else
+  AMVPInfo        m_amvpInfo;
+  AMVPInfo        m_amvpInfo4Pel;
+#endif
+#endif
 
 #if MULTI_HYP_PRED
   MergeCtx        m_geoMrgCtx;
@@ -674,10 +764,26 @@ public:
   /// set ME search range
   void setAdaptiveSearchRange       ( int iDir, int iRefIdx, int iSearchRange) { CHECK(iDir >= MAX_NUM_REF_LIST_ADAPT_SR || iRefIdx>=int(MAX_IDX_ADAPT_SR), "Invalid index"); m_aaiAdaptSR[iDir][iRefIdx] = iSearchRange; }
 #if JVET_AA0070_RRIBC
+#if JVET_AC0112_IBC_CIIP
+  bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost = NULL, PelBuf* ciipIbcBuff = NULL, bool isSecondPass = false, bool* searchedByHash = NULL );
+#else
+#if JVET_AC0112_IBC_LIC
+  bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost = NULL, bool isSecondPass = false, bool* searchedByHash = NULL );
+#else
   bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, bool isSecondPass = false );
+#endif
+#endif
   void  xIntraPatternSearch          ( PredictionUnit& pu, IntTZSearchStruct&  cStruct, Mv& rcMv, Distortion&  ruiCost, Mv* cMvSrchRngLT, Mv* cMvSrchRngRB, Mv* pcMvPred, int rribcFlipType );
+#else
+#if JVET_AC0112_IBC_CIIP
+  bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost = NULL, PelBuf* ciipIbcBuff = NULL, bool* searchedByHash = NULL);
+#else
+#if JVET_AC0112_IBC_LIC
+  bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, Distortion* bvSearchCost = NULL, bool* searchedByHash = NULL);
 #else
   bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap);
+#endif
+#endif
   void  xIntraPatternSearch         ( PredictionUnit& pu, IntTZSearchStruct&  cStruct, Mv& rcMv, Distortion&  ruiCost, Mv* cMvSrchRngLT, Mv* cMvSrchRngRB, Mv* pcMvPred );
 #endif
   void  xSetIntraSearchRange        ( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, const int localSearchRangeX, const int localSearchRangeY, Mv& rcMvSrchRngLT, Mv& rcMvSrchRngRB);
@@ -690,11 +796,19 @@ public:
     m_defaultCachedBvs.currCnt = 0;
   }
 #if JVET_AA0070_RRIBC
+#if JVET_AC0112_IBC_CIIP
+  void xIBCEstimation(PredictionUnit &pu, PelUnitBuf &origBuf, PelBuf &ciipIbcIntraBuff, Mv pcMvPred[3][2], Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY, int numRribcType);
+#else
   void xIBCEstimation(PredictionUnit &pu, PelUnitBuf &origBuf, Mv pcMvPred[3][2], Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY, int numRribcType);
+#endif
   void xIBCSearchMVCandUpdate( Distortion uiSad, int x, int y, Distortion *uiSadBestCand, Mv *cMVCand);
   int  xIBCSearchMVChromaRefine( PredictionUnit &pu, int iRoiWidth, int iRoiHeight, int cuPelX, int cuPelY, Distortion *uiSadBestCand, Mv *cMVCand, int rribcFlipType );
+#else
+#if JVET_AC0112_IBC_CIIP
+  void  xIBCEstimation   ( PredictionUnit& pu, PelUnitBuf& origBuf, PelBuf &ciipIbcIntraBuff, Mv     *pcMvPred, Mv     &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY);
 #else
   void  xIBCEstimation   ( PredictionUnit& pu, PelUnitBuf& origBuf, Mv     *pcMvPred, Mv     &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY);
+#endif
   void  xIBCSearchMVCandUpdate  ( Distortion  uiSad, int x, int y, Distortion* uiSadBestCand, Mv* cMVCand);
   int   xIBCSearchMVChromaRefine( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, int cuPelX, int cuPelY, Distortion* uiSadBestCand, Mv*     cMVCand );
 #endif
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 4d97426276d5b2841b370f6183a23c242739e029..f382e297355dfcac6e58bf4554282c8e7f0852ac 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1621,6 +1621,15 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
     WRITE_UVLC(IBC_MRG_MAX_NUM_CANDS - pcSPS->getMaxNumIBCMergeCand(), "six_minus_max_num_ibc_merge_cand");
 #if JVET_AA0061_IBC_MBVD
     WRITE_FLAG( pcSPS->getUseIbcMbvd() ? 1 : 0,                                         "sps_ibc_mbvd_enabled_flag" );
+#endif
+#if JVET_AC0112_IBC_CIIP
+    WRITE_FLAG( pcSPS->getUseIbcCiip() ? 1 : 0,                                         "sps_ibc_ciip_enabled_flag" );
+#endif
+#if JVET_AC0112_IBC_GPM
+    WRITE_FLAG( pcSPS->getUseIbcGpm() ? 1 : 0,                                          "sps_ibc_gpm_enabled_flag" );
+#endif
+#if JVET_AC0112_IBC_LIC
+    WRITE_FLAG( pcSPS->getUseIbcLic() ? 1 : 0,                                          "sps_ibc_lic_enabled_flag" );
 #endif
   }
 #if !JVET_S0074_SPS_REORDER