diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index d08941ec269763550a7100dd176a1e3831aeb339..a2881df31554040e244d372d2ca78c24a3912e29 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -1204,6 +1204,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setMaxNumGeoCand                                     ( m_maxNumGeoCand );
 #if JVET_AG0164_AFFINE_GPM
   m_cEncLib.setMaxNumGpmAffCand                                  ( m_maxNumGpmAffCand );
+#if JVET_AJ0274_GPM_AFFINE_TM
+  m_cEncLib.setMaxNumGpmAffTmCand                                ( m_maxNumGpmAffTmCand );
+#endif
 #endif
   m_cEncLib.setMaxNumIBCMergeCand                                ( m_maxNumIBCMergeCand );
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 46ed46f41a25fde3a7580bc27a4c0079c75f8d2c..737460da0d59fcf4437eb1a11f688ece2af21650 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1634,6 +1634,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
 #endif
 #if JVET_AG0164_AFFINE_GPM
   ("MaxNumGPMAffCand",                                m_maxNumGpmAffCand,                                  9u, "Maximum number of geometric partitioning mode candidates")
+#if JVET_AJ0274_GPM_AFFINE_TM
+  ("MaxNumGPMAffTmCand",                              m_maxNumGpmAffTmCand,                                6u, "Maximum number of affine candidates for geometric partitioning mode with TM")
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
 #if NON_ADJACENT_MRG_CAND
@@ -4063,6 +4066,9 @@ bool EncAppCfg::xCheckParameter()
 #if JVET_AG0164_AFFINE_GPM
   xConfirmPara( m_maxNumGpmAffCand > GEO_MAX_NUM_UNI_AFF_CANDS, "MaxNumGeoCand must be no more than GEO_MAX_NUM_UNI_CANDS." );
   xConfirmPara( 0 < m_maxNumGpmAffCand && m_maxNumGpmAffCand < 2, "MaxNumGeoCand must be no less than 2 unless MaxNumGeoCand is 0." );
+#if JVET_AJ0274_GPM_AFFINE_TM
+  xConfirmPara( m_maxNumGpmAffTmCand > m_maxNumGpmAffCand, "MaxNumGeoAffTmCand must be no more than MaxNumGeoAffCand." );
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
   xConfirmPara( m_maxNumMHPCand > GEO_MAX_NUM_UNI_CANDS, "m_maxNumMHPCand must be no more than GEO_MAX_NUM_UNI_CANDS." );
@@ -5557,6 +5563,9 @@ void EncAppCfg::xPrintParameter()
   msg( DETAILS, "Max Num Geo Merge Candidates           : %d\n", m_maxNumGeoCand );
 #if JVET_AG0164_AFFINE_GPM
   msg( DETAILS, "Max Num Gpm Affine Merge Candidates    : %d\n", m_maxNumGpmAffCand );
+#if JVET_AJ0274_GPM_AFFINE_TM
+  msg( DETAILS, "Max Num Gpm Affine Tm Merge Candidates : %d\n", m_maxNumGpmAffTmCand );
+#endif
 #endif
 
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index ce2c501cf403d00aeb4aa34255bfce6bde944c50..9a478c16a0901ac17536b60ee3dbf14f38c0769d 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -984,6 +984,9 @@ protected:
   uint32_t      m_maxNumGeoCand;
 #if JVET_AG0164_AFFINE_GPM
   uint32_t      m_maxNumGpmAffCand;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  uint32_t      m_maxNumGpmAffTmCand;
+#endif
 #endif
   uint32_t      m_maxNumIBCMergeCand;                             ///< Max number of IBC merge candidates
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 85128bf80394d79b90fb85f59afd1ebf82044ff7..a5a6c32fc81feba3cbfcafb07e19305a1a398b66 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -1474,6 +1474,9 @@ static const int GEO_MAX_NUM_UNI_AFF_CANDS                          = 11;
 static const int GEO_MAX_ALL_INTER_UNI_CANDS = GEO_MAX_NUM_UNI_CANDS + GEO_MAX_NUM_UNI_AFF_CANDS;
 
 static const int GEO_MAX_NUM_UNI_AFF_CANDS_ARMC                     = 22;
+#if JVET_AJ0274_GPM_AFFINE_TM
+static const int GEO_AFF_TM_MAX_AFF_CANDS                           = 6;
+#endif
 #endif
 
 #if JVET_Y0065_GPM_INTRA
@@ -1555,8 +1558,12 @@ static const int GEO_MAX_TRY_WEIGHTED_SAD =                       140;
 static const int GEO_MAX_TRY_WEIGHTED_SAD =                        70;
 #endif
 #if TM_MRG
+#if JVET_AJ0274_GPM_AFFINE_TM
+static const int GEO_TM_MAX_NUM_CANDS = GEO_MAX_NUM_UNI_CANDS * (GEO_NUM_TM_MV_CAND - 1) + GEO_MAX_NUM_UNI_AFF_CANDS;
+#else
 static const int GEO_TM_MAX_NUM_CANDS = GEO_MAX_NUM_UNI_CANDS * (GEO_NUM_TM_MV_CAND - 1);
 #endif
+#endif
 #else
 static const int GEO_MAX_TRY_WEIGHTED_SAD =                        60;
 #endif
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index cd14376d4e78989092f12946d212faf41521da41..d7884c30f251aaa2e7b090a33bdfd0a41d228652 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -2458,6 +2458,14 @@ void MergeCtx::setGeoMrgDuplicate( const PredictionUnit& pu )
   {
     int mrgList        = mvFieldNeighbours[(mergeCand << 1) + 0].refIdx == -1 ? 1 : 0;
     int mrgRefIdx      = mvFieldNeighbours[(mergeCand << 1) + mrgList].refIdx;
+#if JVET_AJ0274_REGRESSION_GPM_TM
+    if (mrgRefIdx < 0 || mrgRefIdx > MAX_NUM_REF)
+    {
+      mrgDuplicated[mergeCand] = true;
+      pocMrg[mergeCand] = -1;
+      continue;
+    }
+#endif
     pocMrg[mergeCand]  = slice->getRefPic((RefPicList)mrgList, mrgRefIdx)->getPOC();
     mrgMv[mergeCand]   = mvFieldNeighbours[(mergeCand << 1) + mrgList].mv;
     mrgDuplicated[mergeCand] = false;
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index 277ce562fbb42ae5e3515a71251359146c9a4b2f..dfb8a866464d38a71502563f153410df18584909 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -568,6 +568,9 @@ public:
 #endif
 #if JVET_AG0112_REGRESSION_BASED_GPM_BLENDING
   static const CtxSet   GeoBlendFlag;
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  static const CtxSet   GeoBlendTMFlag;
+#endif
 #endif
 #if JVET_W0097_GPM_MMVD_TM
   static const CtxSet   GeoMmvdFlag;
diff --git a/source/Lib/CommonLib/Contexts_ecm14.0.inl b/source/Lib/CommonLib/Contexts_ecm14.0.inl
index ed52c9ee4dabe0aae7feb76d0f468994e373cc37..6503c2c742ae8953f9d1a94c36f5625066466343 100644
--- a/source/Lib/CommonLib/Contexts_ecm14.0.inl
+++ b/source/Lib/CommonLib/Contexts_ecm14.0.inl
@@ -6519,6 +6519,31 @@ const CtxSet ContextSetCfg::SeparateTree = ContextSetCfg::addCtxSet
   { DWO, DWO, DWO },
   });
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+const CtxSet ContextSetCfg::GeoBlendTMFlag = ContextSetCfg::addCtxSet
+({
+  { CNU, },
+  { CNU, },
+  { CNU, },
+  { CNU, },
+  { DWS, },
+  { DWS, },
+  { DWS, },
+  { DWS, },
+  { DWE, },
+  { DWE, },
+  { DWE, },
+  { DWE, },
+  { DWO, },
+  { DWO, },
+  { DWO, },
+  { DWO, },
+  { DWO, },
+  { DWO, },
+  { DWO, },
+  { DWO, },
+  });
+#endif
 #if JVET_AJ0081_CHROMA_TMRL
 const CtxSet ContextSetCfg::ChromaTmrlFlag = ContextSetCfg::addCtxSet
 ({
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 5cc6cea10c7e05d19e6d72ea7ee2d29bbf7a3546..21cac60fe204c4183c37a05380d66773e434a59f 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -1523,6 +1523,9 @@ void InterPrediction::xSubPuBio(PredictionUnit& pu, PelUnitBuf& predBuf, const R
   subPu.mvRefine = pu.mvRefine;
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   subPu.tmMergeFlag = pu.tmMergeFlag;
+#endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  subPu.geoBlendTmFlag = pu.geoBlendTmFlag;
 #endif
   subPu.refIdx[0] = pu.refIdx[0];
   subPu.refIdx[1] = pu.refIdx[1];
@@ -8284,6 +8287,9 @@ void InterPrediction::subBlockOBMC(PredictionUnit  &pu, PelUnitBuf* pDst)
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   subPu.tmMergeFlag = false;
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  subPu.geoBlendTmFlag = false;
+#endif
 #if MULTI_PASS_DMVR
   subPu.bdmvrRefine = false;
 #endif
@@ -9203,10 +9209,17 @@ void InterPrediction::deriveGpmSplitMode(PredictionUnit& pu, MergeCtx &geoMrgCtx
       Pel* pRefLeftPart0[GEO_NUM_TM_MV_CAND] = {nullptr, m_acYuvRefAMLTemplatePart0[1], m_acYuvRefAMLTemplatePart0[3], nullptr                      }; // For mergeCtx[GEO_TM_SHAPE_AL] and mergeCtx[GEO_TM_SHAPE_A]
       Pel* pRefTopPart1 [GEO_NUM_TM_MV_CAND] = {nullptr, m_acYuvRefAMLTemplatePart1[0], nullptr,                       m_acYuvRefAMLTemplatePart1[2]}; // For mergeCtx[GEO_TM_SHAPE_AL] and mergeCtx[GEO_TM_SHAPE_L]
       Pel* pRefLeftPart1[GEO_NUM_TM_MV_CAND] = {nullptr, m_acYuvRefAMLTemplatePart1[1], nullptr,                       m_acYuvRefAMLTemplatePart1[3]}; // For mergeCtx[GEO_TM_SHAPE_AL] and mergeCtx[GEO_TM_SHAPE_L]
+#if JVET_AJ0274_GPM_AFFINE_TM
+      fillPartGPMRefTemplate<0, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_AL], pu.geoMergeIdx0, -1, pRefTopPart0[GEO_TM_SHAPE_AL], pRefLeftPart0[GEO_TM_SHAPE_AL], &affGeoMrgCtx);
+      fillPartGPMRefTemplate<0, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_A ], pu.geoMergeIdx0, -1, pRefTopPart0[GEO_TM_SHAPE_A ], pRefLeftPart0[GEO_TM_SHAPE_A ], &affGeoMrgCtx);
+      fillPartGPMRefTemplate<1, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_AL], pu.geoMergeIdx1, -1, pRefTopPart1[GEO_TM_SHAPE_AL], pRefLeftPart1[GEO_TM_SHAPE_AL], &affGeoMrgCtx);
+      fillPartGPMRefTemplate<1, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_L ], pu.geoMergeIdx1, -1, pRefTopPart1[GEO_TM_SHAPE_L ], pRefLeftPart1[GEO_TM_SHAPE_L ], &affGeoMrgCtx);
+#else
       fillPartGPMRefTemplate<0, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_AL], pu.geoMergeIdx0, -1, pRefTopPart0[GEO_TM_SHAPE_AL], pRefLeftPart0[GEO_TM_SHAPE_AL]);
       fillPartGPMRefTemplate<0, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_A ], pu.geoMergeIdx0, -1, pRefTopPart0[GEO_TM_SHAPE_A ], pRefLeftPart0[GEO_TM_SHAPE_A ]);
       fillPartGPMRefTemplate<1, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_AL], pu.geoMergeIdx1, -1, pRefTopPart1[GEO_TM_SHAPE_AL], pRefLeftPart1[GEO_TM_SHAPE_AL]);
       fillPartGPMRefTemplate<1, false>(pu, geoTmMrgCtx[GEO_TM_SHAPE_L ], pu.geoMergeIdx1, -1, pRefTopPart1[GEO_TM_SHAPE_L ], pRefLeftPart1[GEO_TM_SHAPE_L ]);
+#endif
 
       // Update split mode
       getBestGeoTMModeList(pu, numValidInList, modeList, pRefTopPart0, pRefLeftPart0, pRefTopPart1, pRefLeftPart1);
@@ -9586,14 +9599,126 @@ void InterPrediction::motionCompensationGeoBlend( CodingUnit& cu, MergeCtx& geoM
 #endif
   )
 {
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  MergeCtx geoBlendTmCtx;
+
+  uint8_t maxNumBlendTmMrgCand = geoMrgCtx.numValidMergeCand;
+  geoBlendTmCtx.numValidMergeCand = maxNumBlendTmMrgCand;
+
+  bool mrgDuplicated[GEO_MAX_ALL_INTER_UNI_CANDS];
+  int  pocMrg[GEO_MAX_ALL_INTER_UNI_CANDS];
+  Mv   mrgMv[GEO_MAX_ALL_INTER_UNI_CANDS];
+
+  for (uint8_t mergeCand = 0; mergeCand < maxNumBlendTmMrgCand; mergeCand++)
+  {
+    if (!cu.firstPU->geoBlendTmFlag)
+    {
+      break;
+    }
+    int mrgList = geoMrgCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx == -1 ? 1 : 0;
+    int mrgRefIdx = geoMrgCtx.mvFieldNeighbours[(mergeCand << 1) + mrgList].refIdx;
+
+    pocMrg[mergeCand] = cu.slice->getRefPic((RefPicList)mrgList, mrgRefIdx)->getPOC();
+
+    mrgMv[mergeCand] = geoMrgCtx.mvFieldNeighbours[(mergeCand << 1) + mrgList].mv;
+
+    mrgDuplicated[mergeCand] = false;
+    if (mergeCand)
+    {
+      for (int i = 0; i < mergeCand; i++)
+      {
+        if (pocMrg[mergeCand] == pocMrg[i] && mrgMv[mergeCand] == mrgMv[i])
+        {
+          mrgDuplicated[mergeCand] = true;
+          break;
+        }
+      }
+    }
+  }
+
+  for (int idx = 0; idx < maxNumBlendTmMrgCand; idx++)
+  {
+    if (!cu.firstPU->geoBlendTmFlag)
+    {
+      break;
+    }
+    if (mrgDuplicated[idx])
+    {
+      continue;
+    }
+    geoBlendTmCtx.bcwIdx[idx] = BCW_DEFAULT;
+    geoBlendTmCtx.useAltHpelIf[idx] = false;
+#if JVET_AG0276_NLIC
+    geoBlendTmCtx.altLMFlag[idx] = false;
+    geoBlendTmCtx.altLMParaNeighbours[idx].resetAltLinearModel();
+#endif
+#if INTER_LIC
+    geoBlendTmCtx.licFlags[idx] = geoMrgCtx.licFlags[idx];
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+    geoBlendTmCtx.copyLICParamFromCtx(idx, geoMrgCtx, idx);
+#else
+    geoBlendTmCtx.setDefaultLICParamToCtx(idx);
+#endif
+#endif
+    geoBlendTmCtx.interDirNeighbours[idx] = geoMrgCtx.interDirNeighbours[idx];
+    geoBlendTmCtx.mvFieldNeighbours[(idx << 1)].mv = geoMrgCtx.mvFieldNeighbours[(idx << 1)].mv;
+    geoBlendTmCtx.mvFieldNeighbours[(idx << 1) + 1].mv = geoMrgCtx.mvFieldNeighbours[(idx << 1) + 1].mv;
+    geoBlendTmCtx.mvFieldNeighbours[(idx << 1)].refIdx = geoMrgCtx.mvFieldNeighbours[(idx << 1)].refIdx;
+    geoBlendTmCtx.mvFieldNeighbours[(idx << 1) + 1].refIdx = geoMrgCtx.mvFieldNeighbours[(idx << 1) + 1].refIdx;
+  }
+
+  for (auto& pu : CU::traversePUs(cu))
+  {
+    if (!pu.geoBlendTmFlag)
+    {
+      break;
+    }
+
+    pu.geoTmType = GEO_TM_SHAPE_AL;
+    pu.tmMergeFlag = true;
+    for (uint8_t mrgIdx = 0; mrgIdx < maxNumBlendTmMrgCand; mrgIdx++)
+    {
+      if (mrgDuplicated[mrgIdx])
+      {
+        continue;
+      }
+      geoBlendTmCtx.setMergeInfo(pu, mrgIdx);
+
+#if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE
+      deriveTMMv(pu, NULL, mrgIdx);
+#else
+      deriveTMMv(pu);
+#endif
+
+#if JVET_AE0046_BI_GPM
+      geoBlendTmCtx.interDirNeighbours[mrgIdx] = pu.interDir;
+      geoBlendTmCtx.bcwIdx[mrgIdx] = (pu.interDir != 3) ? BCW_DEFAULT : geoBlendTmCtx.bcwIdx[mrgIdx];
+      geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1)].refIdx = pu.refIdx[0];
+      geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1) + 1].refIdx = pu.refIdx[1];
+#endif
+      geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1)].mv = pu.mv[0];
+      geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1) + 1].mv = pu.mv[1];
+    }
+    pu.tmMergeFlag = false;
+  }
+#endif
   const int mergeIdx = cu.firstPU->geoMergeIdx0;
 
   GeoBlendInfo  geoBI;
+#if JVET_AJ0274_REGRESSION_GPM_TM
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+  cu.licFlag = false;
+  cu.firstPU->geoBlendTmFlag ? geoBlendTmCtx.setLICParamToPu(*cu.firstPU, NOT_VALID, false) : geoMrgCtx.setLICParamToPu(*cu.firstPU, NOT_VALID, false);
+#endif
+  bool  bFoundGeoBlendCand;
+  bFoundGeoBlendCand = cu.firstPU->geoBlendTmFlag ? getGeoBlendCand(cu, geoBlendTmCtx, mergeIdx, geoBI) : getGeoBlendCand(cu, geoMrgCtx, mergeIdx, geoBI);
+#else
 #if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
   cu.licFlag = false;
   geoMrgCtx.setLICParamToPu(*cu.firstPU, NOT_VALID, false);
 #endif
   bool  bFoundGeoBlendCand = getGeoBlendCand( cu, geoMrgCtx, mergeIdx, geoBI );
+#endif
   if ( !bFoundGeoBlendCand ) 
   {
     printf("getGeoBlendCand( mergeIdx=%d ) failed.\n", mergeIdx );
@@ -9613,7 +9738,18 @@ void InterPrediction::motionCompensationGeoBlend( CodingUnit& cu, MergeCtx& geoM
     bool  refinePossible0 = false;
     bool  refinePossible1 = false;
     {
+#if JVET_AJ0274_REGRESSION_GPM_TM
+      if (pu.geoBlendTmFlag)
+      {
+        geoBlendTmCtx.setMergeInfo( pu, geoBI.mergeCand[0] );
+      }
+      else
+      {
+        geoMrgCtx.setMergeInfo( pu, geoBI.mergeCand[0] );
+      }
+#else
       geoMrgCtx.setMergeInfo( pu, geoBI.mergeCand[0] );
+#endif
 
 #if JVET_AE0046_BI_GPM
       refinePossible0 = PU::checkBDMVRCondition(pu, true);
@@ -9636,7 +9772,18 @@ void InterPrediction::motionCompensationGeoBlend( CodingUnit& cu, MergeCtx& geoM
     }
 
     {
+#if JVET_AJ0274_REGRESSION_GPM_TM
+      if (pu.geoBlendTmFlag)
+      {
+        geoBlendTmCtx.setMergeInfo(pu, geoBI.mergeCand[1]);
+      }
+      else
+      {
+        geoMrgCtx.setMergeInfo( pu, geoBI.mergeCand[1] );
+      }
+#else
       geoMrgCtx.setMergeInfo( pu, geoBI.mergeCand[1] );
+#endif
 
 #if JVET_AE0046_BI_GPM
       refinePossible1 = PU::checkBDMVRCondition(pu, true);
@@ -9681,13 +9828,42 @@ void InterPrediction::motionCompensationGeoBlend( CodingUnit& cu, MergeCtx& geoM
 #if JVET_AG0164_AFFINE_GPM
     AffineMergeCtx  dummyAffineMergeCtx;
 #if JVET_AI0082_GPM_WITH_INTER_IBC
+#if JVET_AJ0274_REGRESSION_GPM_TM
+    if (pu.geoBlendTmFlag)
+    {
+      PU::spanGeoMMVDMotionInfo(pu, geoBlendTmCtx
+        , dummyAffineMergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+        , dummyAffineMergeCtx
+#endif
+        , geoBlendTmCtx, geoBlendTmCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, nullptr
+        , pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, subBdofBuf[geoMergeIdx0], subBdofBuf[geoMergeIdx1]);
+    }
+    else
+    {
+      PU::spanGeoMMVDMotionInfo(pu, geoMrgCtx
+        , dummyAffineMergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+        , dummyAffineMergeCtx
+#endif
+        , geoMrgCtx, geoMrgCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, nullptr
+        , pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, subBdofBuf[geoMergeIdx0], subBdofBuf[geoMergeIdx1]);
+    }
+#else
     PU::spanGeoMMVDMotionInfo( pu, geoMrgCtx
       , dummyAffineMergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+      , dummyAffineMergeCtx
+#endif
       , geoMrgCtx, geoMrgCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, nullptr
       , pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, subBdofBuf[geoMergeIdx0], subBdofBuf[geoMergeIdx1] );
+#endif
 #else
     PU::spanGeoMMVDMotionInfo( pu, geoMrgCtx
       , dummyAffineMergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+      , dummyAffineMergeCtx
+#endif
       , geoMrgCtx, geoMrgCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM
       , pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, subBdofBuf[geoMergeIdx0], subBdofBuf[geoMergeIdx1] );
 #endif
@@ -9719,6 +9895,9 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
 #endif
 #if JVET_AG0164_AFFINE_GPM
                                            , AffineMergeCtx& gpmAffMrgCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+                                           , AffineMergeCtx &gpmAffTmMrgCtx
+#endif
 #endif
 #if JVET_AE0046_BI_GPM
                                           , Mv(&subMvBuf)[MRG_MAX_NUM_CANDS << 1][MAX_NUM_SUBCU_DMVR]
@@ -9787,8 +9966,12 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
                    , geoTmMrgCtx
 #endif
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+                    , (cu.firstPU->geoTmFlag0 && (cu.firstPU->affineGPM[0] || cu.firstPU->affineGPM[1])) ? gpmAffTmMrgCtx : gpmAffMrgCtx
+#else
                    , gpmAffMrgCtx
 #endif
+#endif
 #if JVET_Y0065_GPM_INTRA
                    , pcIntraPred
 #endif
@@ -9910,6 +10093,21 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
 #if TM_MRG
     if (geoTmFlag0)
     {
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (pu.affineGPM[0])
+      {
+        gpmAffTmMrgCtx.setAffMergeInfo(pu, candIdx0, geoMMVDFlag0 ? geoMMVDIdx0 : -1);
+        if (pu.refIdx[0] >= 0)// Prepare MV for chroma
+        {
+          PU::setAllAffineMv(pu, pu.mvAffi[0][0], pu.mvAffi[0][1], pu.mvAffi[0][2], REF_PIC_LIST_0);
+        }
+        if (pu.refIdx[1] >= 0)
+        {
+          PU::setAllAffineMv(pu, pu.mvAffi[1][0], pu.mvAffi[1][1], pu.mvAffi[1][2], REF_PIC_LIST_1);
+        }
+      }
+      else
+#endif
       geoTmMrgCtx0.setMergeInfo(pu, candIdx0);
     }
     else
@@ -10006,6 +10204,10 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
 #endif
 #else
         PU::spanMotionInfo(pu);
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (!geoTmFlag0)
+      {
 #endif
       cu.isobmcMC = true;
 #if JVET_AJ0161_OBMC_EXT_WITH_INTRA_PRED
@@ -10014,6 +10216,9 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
       subBlockOBMC(pu, &tmpGeoBuf0);
 #endif
       cu.isobmcMC = false;
+#if JVET_AJ0274_GPM_AFFINE_TM
+      }
+#endif
 #if JVET_AG0164_AFFINE_GPM
       if (pu.affineGPM[0])
       {
@@ -10085,6 +10290,21 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
 #if TM_MRG
     if (geoTmFlag1)
     {
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (pu.affineGPM[1])
+      {
+        gpmAffTmMrgCtx.setAffMergeInfo(pu, candIdx1, geoMMVDFlag1? geoMMVDIdx1: -1);
+        if (pu.refIdx[0] >= 0)
+        {
+          PU::setAllAffineMv(pu, pu.mvAffi[0][0], pu.mvAffi[0][1], pu.mvAffi[0][2], REF_PIC_LIST_0);
+        }
+        if (pu.refIdx[1] >= 0)
+        {
+          PU::setAllAffineMv(pu, pu.mvAffi[1][0], pu.mvAffi[1][1], pu.mvAffi[1][2], REF_PIC_LIST_1);
+        }
+      }
+      else
+#endif
       geoTmMrgCtx1.setMergeInfo(pu, candIdx1);
     }
     else
@@ -10179,6 +10399,10 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
 #endif
 #else
         PU::spanMotionInfo(pu);
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (!geoTmFlag1)
+      {
 #endif
       cu.isobmcMC = true;
 #if JVET_AJ0161_OBMC_EXT_WITH_INTRA_PRED
@@ -10187,6 +10411,9 @@ void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx
       subBlockOBMC(pu, &tmpGeoBuf1);
 #endif
       cu.isobmcMC = false;
+#if JVET_AJ0274_GPM_AFFINE_TM
+      }
+#endif
 #if JVET_AG0164_AFFINE_GPM
       if (pu.affineGPM[1])
       {
@@ -13882,9 +14109,13 @@ Distortion InterPrediction::deriveBcwBlending( PredictionUnit& pu, bool bUniDir[
       for (int x = 0; x < width; x++)
       {
         int posX = x - (iTemp ? AML_MERGE_TEMPLATE_SIZE : 0);
-
+#if JVET_AJ0274_REGRESSION_GPM_TM
+        const Pel P0 = bUniDir0 ? ClipPel( (Pel)rightShift((p0[x] + offset), shiftNum), clpRng ) : p0[x];
+        const Pel P1 = bUniDir1 ? ClipPel( (Pel)rightShift((p1[x] + offset), shiftNum), clpRng ) : p1[x];
+#else
         const Pel P0 = ClipPel( (Pel)rightShift((p0[x] + offset), shiftNum), clpRng );
         const Pel P1 = ClipPel( (Pel)rightShift((p1[x] + offset), shiftNum), clpRng );
+#endif
 
         int iWeight = blendModel.compute( posX, posY );
 
@@ -19436,6 +19667,17 @@ void InterPrediction::getAffAndSbtmvpRefTemplate(PredictionUnit& pu, PelUnitBuf&
         Pel *recLeftTemplate = m_acYuvCurAMLTemplate[1][0];
         Pel *recAboveTemplate = m_acYuvCurAMLTemplate[0][0];
         xGetLICParamGeneral(*pu.cu, COMPONENT_Y, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate, recAboveTemplate, LICshift[refList], scale[refList], offset[refList]);
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG && JVET_AJ0274_GPM_AFFINE_TM
+        if (pu.cu->licInheritPara && pu.cu->geoFlag && pu.cs->sps->getMaxNumGpmAffTmCand() > 0)
+        {
+          LICshift[0] = m_LICShift;
+          scale[0] = pu.cu->licScale[0][0];
+          offset[0] = pu.cu->licOffset[0][0];
+          LICshift[1] = m_LICShift;
+          scale[1] = pu.cu->licScale[1][0];
+          offset[1] = pu.cu->licOffset[1][0];
+        }
+#endif
       }
 #endif
     }
@@ -23982,7 +24224,11 @@ void InterPrediction::deriveTMMv(PredictionUnit& pu, Distortion* tmCost)
 void InterPrediction::deriveTMMv(PredictionUnit& pu)
 #endif
 {
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  if (!pu.tmMergeFlag && !pu.geoBlendTmFlag)
+#else
   if( !pu.tmMergeFlag )
+#endif
   {
     return;
   }
@@ -27877,7 +28123,11 @@ bool InterPrediction::processTM4Affine(PredictionUnit& pu, AffineMergeCtx &affin
     }
   }
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (uiCostBest < REFINE_THRESHOLD_AFFINE_MERGE * uiCostOri && !pu.cu->geoFlag)
+#else
   if (uiCostBest < REFINE_THRESHOLD_AFFINE_MERGE * uiCostOri)
+#endif
   {
     if (!isEncoder && uiAffMergeCand > -1)
     {
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index bd92d7aef0143a5acc0ab45fad1c2ba57eb75a7e..4b48043137a3a3c1c2ff9c6a0bc7f85ea49e4271 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -834,6 +834,9 @@ public:
 #endif
 #if JVET_AG0164_AFFINE_GPM
                               , AffineMergeCtx &gpmAffMrgCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+                              , AffineMergeCtx &gpmAffTmMrgCtx
+#endif
 #endif
 #if JVET_AE0046_BI_GPM
                               , Mv(&subMvBuf)[MRG_MAX_NUM_CANDS << 1][MAX_NUM_SUBCU_DMVR]
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 3cb175e8601c35113507d62890fd0d2e839fbe46..7bfe88ad40e95a43ea8488a6ea034ebe4fcf4fd2 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -4417,6 +4417,9 @@ SPS::SPS()
 , m_maxNumGeoCand(0)
 #if JVET_AG0164_AFFINE_GPM
 , m_maxNumGpmAffCand(0)
+#if JVET_AJ0274_GPM_AFFINE_TM
+, m_maxNumGpmAffTmCand(0)
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
 , m_maxNumMHPCand(0)
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 9e017aec4c2ea8163cf0c4aded113d776d23c8c4..b01dc83f23ccbbe8dc85723022eff69c152c357d 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1963,6 +1963,9 @@ private:
   uint32_t          m_maxNumGeoCand;
 #if JVET_AG0164_AFFINE_GPM
   uint32_t          m_maxNumGpmAffCand;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  uint32_t          m_maxNumGpmAffTmCand;
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
   uint32_t          m_maxNumMHPCand;
@@ -2431,6 +2434,10 @@ void                    setCCALFEnabledFlag( bool b )
 #if JVET_AG0164_AFFINE_GPM
   uint32_t                getMaxNumGpmAffCand() const                                                     { CHECK(m_maxNumGpmAffCand > GEO_MAX_NUM_UNI_AFF_CANDS, "Number of GPM Affine candidates exceed GEO_MAX_NUM_UNI_AFF_CANDS"); return m_maxNumGpmAffCand; }
   void                    setMaxNumGpmAffCand(uint32_t u)                                                 { CHECK(m_maxNumGpmAffCand > GEO_MAX_NUM_UNI_AFF_CANDS, "Number of GPM Affine  candidates exceed GEO_MAX_NUM_UNI_AFF_CANDS"); m_maxNumGpmAffCand = u; }
+#if JVET_AJ0274_GPM_AFFINE_TM
+  uint32_t                getMaxNumGpmAffTmCand() const                                                   { return m_maxNumGpmAffTmCand; }
+  void                    setMaxNumGpmAffTmCand(uint32_t u)                                               { m_maxNumGpmAffTmCand = u; }
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
   uint32_t                getMaxNumMHPCand() const                                                        { CHECK( m_maxNumMHPCand >= GEO_MAX_NUM_UNI_CANDS, "Number of MHP candidates exceed GEO_MAX_NUM_CANDS" ); return m_maxNumMHPCand; }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index dd2bbe4da7313e5932129ccac854b592154c7dc6..1ede9be2a2950c0ec242f0ba37d1c63e524a4368 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -345,8 +345,12 @@
 #define JVET_AF0159_AFFINE_SUBPU_BDOF_REFINEMENT          1 // JVET-AF0159: Affine subblock BDOF refinement
 #define JVET_AF0057                                       1 // JVET-AF0057: Encoder only. DMVR with robust MV derivation.
 #define JVET_AG0112_REGRESSION_BASED_GPM_BLENDING         1 // JVET-AG0112: Regression-based GPM blending
+#define JVET_AJ0274_REGRESSION_GPM_TM                     1 // JVET-AJ0274: Regression-based GPM with TM extension
 #define JVET_AG0135_AFFINE_CIIP                           1 // JVET-AG0135: CIIP with affine prediction 
 #define JVET_AG0164_AFFINE_GPM                            1 // JVET-AG0164: GPM with affine prediction
+#if JVET_AG0164_AFFINE_GPM
+#define JVET_AJ0274_GPM_AFFINE_TM                         1 // JVET-AJ0274: GPM-affine with TM
+#endif
 #define JVET_AG0098_AMVP_WITH_SBTMVP                      1 // JVET-AG0098: AMVP with SbTMVP mode
 #define JVET_AG0067_DMVR_EXTENSIONS                       1 // JVET-AG0067: On DMVR Extensions
 #define JVET_AH0069_CMVP                                  1 // JVET-AH0069: Chained motion vector prediction
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 98d8503763edec102b26c3dd3a4053c9648ab8a1..f5668d98a98cb365544e8830446436b7079f65ea 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -1141,6 +1141,9 @@ void PredictionUnit::initData()
   geoTmFlag1 = false;
 #endif
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  geoBlendTmFlag = false;
+#endif
 #if JVET_AA0058_GPM_ADAPTIVE_BLENDING
   geoBldIdx = MAX_UCHAR;
 #endif
@@ -1372,6 +1375,9 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData)
   geoTmFlag1 = predData.geoTmFlag1;
 #endif
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  geoBlendTmFlag = predData.geoBlendTmFlag;
+#endif
 #if JVET_AA0058_GPM_ADAPTIVE_BLENDING
   geoBldIdx = predData.geoBldIdx;
 #endif
@@ -1612,6 +1618,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
   geoTmFlag1 = other.geoTmFlag1;
 #endif
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  geoBlendTmFlag = other.geoBlendTmFlag;
+#endif
 #if JVET_AA0058_GPM_ADAPTIVE_BLENDING
   geoBldIdx = other.geoBldIdx;
 #endif
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index e62a44e5bcdbe2be7d8fd8d915b961ac97244939..ff1fb6048eea2839f3ef92499c8f3a360c762d51 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -680,6 +680,9 @@ struct InterPredictionData
   uint8_t     geoTmType;
 #endif
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  bool        geoBlendTmFlag;
+#endif
 #if JVET_AA0058_GPM_ADAPTIVE_BLENDING
   uint8_t     geoBldIdx;
 #endif
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 5c98aea75fe1b5b81408ccadf671668198b623e7..15adfcfcceaa6a51cd40dbadd61671c5f8394bfc 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -197,6 +197,41 @@ bool CU::isOnCtuBottom( const CodingUnit& cu )
   return cuBottomY % ctuHeight == 0;
 }
 
+#if JVET_AJ0274_REGRESSION_GPM_TM
+bool CU::checkGeoBlendTmAvail(const CodingUnit& currCU, const CodingStructure* bestCS)
+{
+  const CodingUnit* bestCUTest = bestCS->getCU(CHANNEL_TYPE_LUMA);
+  bool skipGeoBlendTM = false;
+
+  if (currCU.slice->getCheckLDC() && !currCU.slice->getCheckLDB() && bestCUTest->skip && !bestCUTest->affine && !bestCUTest->mmvdSkip && !bestCUTest->geoFlag && !bestCUTest->firstPU->tmMergeFlag)
+  {
+    skipGeoBlendTM = true;
+  }
+  else if (currCU.slice->getCheckLDC() && !currCU.slice->getCheckLDB() && bestCUTest->affine)
+  {
+    skipGeoBlendTM = true;
+  }
+  else if (currCU.slice->getCheckLDC() && !currCU.slice->getCheckLDB() && !bestCUTest->skip && bestCUTest->geoFlag && bestCUTest->firstPU->gpmIntraFlag)
+  {
+    skipGeoBlendTM = true;
+  }
+  else if (currCU.slice->getCheckLDB() && !bestCUTest->skip && bestCUTest->geoFlag && (bestCUTest->firstPU->geoMMVDFlag0 || bestCUTest->firstPU->geoMMVDFlag1)
+    && !bestCUTest->firstPU->gpmIntraFlag && !bestCUTest->firstPU->affineGPM[0] && !bestCUTest->firstPU->affineGPM[1])
+  {
+    skipGeoBlendTM = true;
+  }
+  else if (currCU.slice->getCheckLDB() && bestCUTest->skip && !bestCUTest->affine && !bestCUTest->mmvdSkip && !bestCUTest->geoFlag && !bestCUTest->firstPU->tmMergeFlag)
+  {
+    skipGeoBlendTM = true;
+  }
+  else if (!currCU.slice->getCheckLDC() && bestCUTest->skip && !bestCUTest->affine && !bestCUTest->mmvdSkip && !bestCUTest->geoFlag && !bestCUTest->firstPU->tmMergeFlag)
+  {
+    skipGeoBlendTM = true;
+  }
+  return skipGeoBlendTM;
+}
+#endif
+
 #if JVET_AI0136_ADAPTIVE_DUAL_TREE
 bool CU::isPartitionerOnCtuBottom( const CodingUnit& cu, const Partitioner& partitioner )
 {
@@ -29638,6 +29673,9 @@ void PU::spanGeoIBCMotionInfo(PredictionUnit &pu, MergeCtx &geoMrgCtx)
 void PU::spanGeoMMVDMotionInfo(PredictionUnit& pu, MergeCtx& geoMrgCtx 
 #if JVET_AG0164_AFFINE_GPM
   , AffineMergeCtx& geoAffMrgCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+  , AffineMergeCtx& geoAffTmMrgCtx
+#endif
 #endif
   , MergeCtx& geoTmMrgCtx0, MergeCtx& geoTmMrgCtx1, const uint8_t splitDir, const uint8_t mergeIdx0, const uint8_t mergeIdx1, const bool tmFlag0, const bool mmvdFlag0, const uint8_t mmvdIdx0, const bool tmFlag1, const bool mmvdFlag1, const uint8_t mmvdIdx1, const uint8_t bldIdx, const uint8_t *intraMPM,
 #if JVET_AI0082_GPM_WITH_INTER_IBC
@@ -29990,12 +30028,21 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
   int affMvBufStride = MAX_CU_SIZE >> 2;
   if (pu.affineGPM[0])
   {
+#if JVET_AJ0274_GPM_AFFINE_TM
+    pu.gpmPartAffType[0] = tmFlag0 ? geoAffTmMrgCtx.affineType[mergeIdx0] : geoAffMrgCtx.affineType[mergeIdx0];
+#else
     pu.gpmPartAffType[0] = geoAffMrgCtx.affineType[mergeIdx0];
+#endif
     CHECK(pu.gpmPartAffType[0] == AFFINE_MODEL_NUM, "Invalid affine type");
     pu.gpmPartRefIdx[0][0] = pu.gpmPartRefIdx[0][1] = -1;
 
+#if JVET_AJ0274_GPM_AFFINE_TM
+    pu.cu->affineType = tmFlag0 ? geoAffTmMrgCtx.affineType[mergeIdx0] : geoAffMrgCtx.affineType[mergeIdx0];
+    MvField* cpmvMvField0 = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[mergeIdx0 << 1] : geoAffMrgCtx.mvFieldNeighbours[mergeIdx0 << 1];
+#else
     pu.cu->affineType = geoAffMrgCtx.affineType[mergeIdx0];
     MvField* cpmvMvField0 = geoAffMrgCtx.mvFieldNeighbours[mergeIdx0 << 1];
+#endif
     if (cpmvMvField0[0].refIdx >= 0)
     {
       PU::setAllAffineMv(pu, cpmvMvField0[0].mv + deltaMv, cpmvMvField0[1].mv + deltaMv, cpmvMvField0[2].mv + deltaMv, REF_PIC_LIST_0);
@@ -30006,7 +30053,11 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
       pu.gpmPartmvAffi[0][0][2] = cpmvMvField0[2].mv + deltaMv;
 
     }
+#if JVET_AJ0274_GPM_AFFINE_TM
+    MvField* cpmvMvField1 = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[(mergeIdx0 << 1) + 1] : geoAffMrgCtx.mvFieldNeighbours[(mergeIdx0 << 1) + 1];
+#else
     MvField* cpmvMvField1 = geoAffMrgCtx.mvFieldNeighbours[(mergeIdx0 << 1) + 1];
+#endif
     if (cpmvMvField1[0].refIdx >= 0)
     {
       PU::setAllAffineMv(pu, cpmvMvField1[0].mv + deltaMv, cpmvMvField1[1].mv + deltaMv, cpmvMvField1[2].mv + deltaMv, REF_PIC_LIST_1);
@@ -30033,12 +30084,21 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
   }
   if (pu.affineGPM[1])
   {
+#if JVET_AJ0274_GPM_AFFINE_TM
+    pu.gpmPartAffType[1] = tmFlag0 ? geoAffTmMrgCtx.affineType[mergeIdx1] : geoAffMrgCtx.affineType[mergeIdx1];
+#else
     pu.gpmPartAffType[1] = geoAffMrgCtx.affineType[mergeIdx1];
+#endif
     CHECK(pu.gpmPartAffType[1] == AFFINE_MODEL_NUM, "Invalid affine type");
     pu.gpmPartRefIdx[1][0] = pu.gpmPartRefIdx[1][1] = -1;
 
+#if JVET_AJ0274_GPM_AFFINE_TM
+    pu.cu->affineType = tmFlag0 ? geoAffTmMrgCtx.affineType[mergeIdx1] : geoAffMrgCtx.affineType[mergeIdx1];
+    MvField* cpmvMvField0 = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1)] : geoAffMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1)];
+#else
     pu.cu->affineType = geoAffMrgCtx.affineType[mergeIdx1];
     MvField* cpmvMvField0 = geoAffMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1)];
+#endif
     if (cpmvMvField0[0].refIdx >= 0)
     {
       PU::setAllAffineMv(pu, cpmvMvField0[0].mv + deltaMv, cpmvMvField0[1].mv + deltaMv, cpmvMvField0[2].mv + deltaMv, REF_PIC_LIST_0);
@@ -30048,7 +30108,11 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
       pu.gpmPartmvAffi[1][0][1] = cpmvMvField0[1].mv + deltaMv;
       pu.gpmPartmvAffi[1][0][2] = cpmvMvField0[2].mv + deltaMv;
     }
+#if JVET_AJ0274_GPM_AFFINE_TM
+    MvField* cpmvMvField1 = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1) + 1] : geoAffMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1) + 1];
+#else
     MvField* cpmvMvField1 = geoAffMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1) + 1];
+#endif
     if (cpmvMvField1[0].refIdx >= 0)
     {
       PU::setAllAffineMv(pu, cpmvMvField1[0].mv + deltaMv, cpmvMvField1[1].mv + deltaMv, cpmvMvField1[2].mv + deltaMv, REF_PIC_LIST_1);
@@ -30264,9 +30328,15 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
 #if JVET_AG0164_AFFINE_GPM
         if (pu.affineGPM[0])
         {
+#if JVET_AJ0274_GPM_AFFINE_TM
+          mb.at(x, y).interDir = tmFlag0 ? geoAffTmMrgCtx.interDirNeighbours[mergeIdx0] : geoAffMrgCtx.interDirNeighbours[mergeIdx0];
+          mb.at(x, y).refIdx[0] = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[mergeIdx0 << 1][0].refIdx : geoAffMrgCtx.mvFieldNeighbours[mergeIdx0 << 1][0].refIdx;
+          mb.at(x, y).refIdx[1] = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[(mergeIdx0 << 1) + 1][0].refIdx :geoAffMrgCtx.mvFieldNeighbours[(mergeIdx0 << 1) + 1][0].refIdx;
+#else
           mb.at(x, y).interDir = geoAffMrgCtx.interDirNeighbours[mergeIdx0];
           mb.at(x, y).refIdx[0] = geoAffMrgCtx.mvFieldNeighbours[mergeIdx0 << 1][0].refIdx;
           mb.at(x, y).refIdx[1] = geoAffMrgCtx.mvFieldNeighbours[(mergeIdx0 << 1) + 1][0].refIdx;
+#endif
           mb.at(x, y).mv[0] = pMvBufP0L0[x];
           mb.at(x, y).mv[1] = pMvBufP0L1[x];
         }
@@ -30344,9 +30414,15 @@ void PU::spanGeoMMVDMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const u
 #if JVET_AG0164_AFFINE_GPM
         if (pu.affineGPM[1])
         {
+#if JVET_AJ0274_GPM_AFFINE_TM
+          mb.at(x, y).interDir = tmFlag0 ? geoAffTmMrgCtx.interDirNeighbours[mergeIdx1] : geoAffMrgCtx.interDirNeighbours[mergeIdx1];
+          mb.at(x, y).refIdx[0] = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[mergeIdx1 << 1][0].refIdx : geoAffMrgCtx.mvFieldNeighbours[mergeIdx1 << 1][0].refIdx;
+          mb.at(x, y).refIdx[1] = tmFlag0 ? geoAffTmMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1) + 1][0].refIdx : geoAffMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1) + 1][0].refIdx;
+#else
           mb.at(x, y).interDir = geoAffMrgCtx.interDirNeighbours[mergeIdx1];
           mb.at(x, y).refIdx[0] = geoAffMrgCtx.mvFieldNeighbours[mergeIdx1 << 1][0].refIdx;
           mb.at(x, y).refIdx[1] = geoAffMrgCtx.mvFieldNeighbours[(mergeIdx1 << 1) + 1][0].refIdx;
+#endif
           mb.at(x, y).mv[0] = pMvBufP1L0[x];
           mb.at(x, y).mv[1] = pMvBufP1L1[x];
         }
@@ -33280,6 +33356,25 @@ bool PU::isAffineGPMValid(const PredictionUnit& pu)
   return true;
 }
 
+#if JVET_AJ0274_GPM_AFFINE_TM
+bool PU::isAffineGpmTmValid(const PredictionUnit& pu)
+{
+  if (pu.cu->slice->getSPS()->getMaxNumGpmAffTmCand() <= 0)
+  {
+    return false;
+  }
+  if (pu.lwidth() * pu.lheight() >= 4096)
+  {
+    return false;
+  }
+  if ((pu.cs->slice->getTLayer() <= 1 && !pu.cs->slice->getCheckLDC()) || pu.cs->slice->getTLayer() >= 5)
+  {
+    return false;
+  }
+  return true;
+}
+#endif
+
 void PU::getGeoAffMergeCandidates(PredictionUnit& pu, AffineMergeCtx& gpmAffMrgCtx, InterPrediction* pcInterPred
 #if !JVET_AH0314_LIC_INHERITANCE_FOR_MRG
                                 , AffineMergeCtx* affMergeCtx
@@ -33436,6 +33531,13 @@ void PU::getGeoAffMergeCandidates(PredictionUnit& pu, AffineMergeCtx& gpmAffMrgC
 #if JVET_AH0314_LIC_INHERITANCE_FOR_MRG && JVET_AG0164_AFFINE_GPM
 #if JVET_AG0276_NLIC
       bool isLic = tmpMergeCtx.licFlags[i];
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      bool useInheritedOrig = useInherited;
+      if (tmpMergeCtx.interDirNeighbours[i] == 3 && pu.cs->sps->getMaxNumGpmAffTmCand() > 0)
+      {
+        useInherited = false;
+      }
 #endif
       gpmAffMrgCtx.licFlags[gpmAffMrgCtx.numValidMergeCand] = false;
       gpmAffMrgCtx.licInheritPara[gpmAffMrgCtx.numValidMergeCand] = false;
@@ -33461,6 +33563,9 @@ void PU::getGeoAffMergeCandidates(PredictionUnit& pu, AffineMergeCtx& gpmAffMrgC
 #endif
       }
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      useInherited = useInheritedOrig;
+#endif
 
       if (gpmAffMrgCtx.xCheckSimilarMotion(gpmAffMrgCtx.numValidMergeCand))
       {
@@ -33491,6 +33596,13 @@ void PU::getGeoAffMergeCandidates(PredictionUnit& pu, AffineMergeCtx& gpmAffMrgC
 #if JVET_AH0314_LIC_INHERITANCE_FOR_MRG && JVET_AG0164_AFFINE_GPM
 #if JVET_AG0276_NLIC
       bool isLic = tmpMergeCtx.licFlags[i];
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      bool useInheritedOrig = useInherited;
+      if (tmpMergeCtx.interDirNeighbours[i] == 3 && pu.cs->sps->getMaxNumGpmAffTmCand() > 0)
+      {
+        useInherited = false;
+      }
 #endif
       gpmAffMrgCtx.licFlags[gpmAffMrgCtx.numValidMergeCand] = false;
       gpmAffMrgCtx.licInheritPara[gpmAffMrgCtx.numValidMergeCand] = false;
@@ -33515,6 +33627,9 @@ void PU::getGeoAffMergeCandidates(PredictionUnit& pu, AffineMergeCtx& gpmAffMrgC
         }
 #endif
       }
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      useInherited = useInheritedOrig;
 #endif
       if (gpmAffMrgCtx.xCheckSimilarMotion(gpmAffMrgCtx.numValidMergeCand))
       {
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 287548ad3a70a7d8b1819dedf0ff8b45f0b59f16..cee2761cc416394ccd0ec33fb7f2cfe96fc753f0 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -172,6 +172,9 @@ namespace CU
   uint8_t numSbtModeRdo               (uint8_t sbtAllowed);
   bool    isSbtMode                   (const uint8_t sbtInfo);
   bool    isSameSbtSize               (const uint8_t sbtInfo1, const uint8_t sbtInfo2);
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  bool    checkGeoBlendTmAvail        (const CodingUnit& currCU, const CodingStructure* bestCS);
+#endif
 #if JVET_AI0050_SBT_LFNST
   void    getSBTPosAndSize            (const CodingUnit &cu, Position& pos, Size& size, uint8_t sbtMode);
 #endif
@@ -822,6 +825,9 @@ namespace PU
   bool isAffineGPMSizeValid(const PredictionUnit& pu);
 
   int  getAffGPMCtxOffset(const PredictionUnit& pu);
+#if JVET_AJ0274_GPM_AFFINE_TM
+  bool isAffineGpmTmValid(const PredictionUnit& pu);
+#endif
 #endif
 #if JVET_W0097_GPM_MMVD_TM
 #if TM_MRG
@@ -852,6 +858,9 @@ namespace PU
   void spanGeoMMVDMotionInfo(PredictionUnit& pu, MergeCtx& geoMrgCtx 
 #if JVET_AG0164_AFFINE_GPM
      , AffineMergeCtx& geoAffMrgCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+     , AffineMergeCtx& geoAffTmMrgCtx
+#endif
 #endif
     , MergeCtx& geoTmMrgCtx0, MergeCtx& geoTmMrgCtx1, const uint8_t splitDir, const uint8_t mergeIdx0, const uint8_t mergeIdx1, const bool tmFlag0, const bool mmvdFlag0, const uint8_t mmvdIdx0, const bool tmFlag1, const bool mmvdFlag1, const uint8_t mmvdIdx1, const uint8_t bldIdx,const uint8_t *intraMPM,
 #if JVET_AI0082_GPM_WITH_INTER_IBC
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index c5745f088570646040f59417a12f5754e3bd5b37..920b902b64ad4ef254b8913d4ab439144bc97ebd 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -5888,6 +5888,9 @@ void CABACReader::merge_data( PredictionUnit& pu )
         pu.cu->geoFlag = true;
 #if JVET_AG0112_REGRESSION_BASED_GPM_BLENDING
         pu.cu->geoBlendFlag = false;
+#if JVET_AJ0274_REGRESSION_GPM_TM
+        pu.geoBlendTmFlag = false;
+#endif
 #endif
 #if JVET_AE0046_BI_GPM
         PU::setGpmDirMode(pu);
@@ -6009,6 +6012,9 @@ void CABACReader::merge_idx( PredictionUnit& pu )
         pu.gpmIntraFlag = false;
 #if JVET_AI0082_GPM_WITH_INTER_IBC
         pu.gpmInterIbcFlag = false;
+#endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+        pu.geoBlendTmFlag = m_BinDecoder.decodeBin(Ctx::GeoBlendTMFlag());
 #endif
         return;
       }
@@ -6101,6 +6107,9 @@ void CABACReader::merge_idx( PredictionUnit& pu )
       pu.gpmInterIbcFlag = (isIbc0 || isIbc1);
 #endif
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      bool affGpmTmValid = isAffGPMValid && PU::isAffineGpmTmValid(pu);
+#endif
 
 #if TM_MRG
       if (!pu.geoMMVDFlag0 && !pu.geoMMVDFlag1)
@@ -6112,12 +6121,20 @@ void CABACReader::merge_idx( PredictionUnit& pu )
         }
         else
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (!affGpmTmValid && (pu.affineGPM[0] || pu.affineGPM[1]))
+        {
+          pu.tmMergeFlag = false;
+        }
+        else
+#else
 #if JVET_AG0164_AFFINE_GPM
         if (pu.affineGPM[0] || pu.affineGPM[1])
         {
           pu.tmMergeFlag = false;
         }
         else
+#endif
 #endif
         tm_merge_flag(pu);
         if (pu.tmMergeFlag)
@@ -6455,6 +6472,12 @@ void CABACReader::geo_merge_idx(PredictionUnit& pu)
   int maxNumGeoCand = pu.affineGPM[0] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
 #else
   const int maxNumGeoCand = pu.cs->sps->getMaxNumGeoCand();
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[0] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
 #endif
   CHECK(maxNumGeoCand < 2, "Incorrect max number of geo candidates");
   CHECK(pu.cu->lheight() > 64 || pu.cu->lwidth() > 64, "Incorrect block size of geo flag");
@@ -6481,6 +6504,12 @@ void CABACReader::geo_merge_idx(PredictionUnit& pu)
 
 #if JVET_AG0164_AFFINE_GPM
   maxNumGeoCand = pu.affineGPM[1] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[1] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
   numCandminus2 = maxNumGeoCand - 2;
 #endif
 
@@ -6541,6 +6570,12 @@ void CABACReader::geo_merge_idx1(PredictionUnit& pu)
 #endif
 #if JVET_AG0164_AFFINE_GPM
   int maxNumGeoCand = pu.affineGPM[0] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[0] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
 #else
   const int maxNumGeoCand = pu.cs->sps->getMaxNumGeoCand();
 #endif
@@ -6615,6 +6650,12 @@ void CABACReader::geo_merge_idx1(PredictionUnit& pu)
 
 #if JVET_AG0164_AFFINE_GPM
   maxNumGeoCand = pu.affineGPM[1] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[1] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
   numCandminus2 = maxNumGeoCand - 2;
 #endif
 
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index ab9ed528cfedc512bac4a1b9ee543b66ab62fbef..855ef3a4d52665b351077c5222667a0289f58441 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -1974,6 +1974,9 @@ void DecCu::xReconInter(CodingUnit &cu)
 #endif
 #if JVET_AG0164_AFFINE_GPM
                                         , m_geoAffMrgCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+                                        , m_geoAffTmMrgCtx
+#endif
 #endif
 #if JVET_AE0046_BI_GPM
                                         , m_mvBufBDMVR
@@ -1998,6 +2001,9 @@ void DecCu::xReconInter(CodingUnit &cu)
                              ( *cu.firstPU, m_geoMrgCtx
 #if JVET_AG0164_AFFINE_GPM
                                , m_geoAffMrgCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+                               , m_geoAffTmMrgCtx
+#endif
 #endif
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
 							                , m_geoTmMrgCtx0, m_geoTmMrgCtx1
@@ -3041,6 +3047,9 @@ void DecCu::xDeriveCUMV(CodingUnit &cu)
 
              m_geoAffMrgCtx.numValidMergeCand = std::min(m_geoAffMrgCtx.numValidMergeCand, (int)pu.cs->sps->getMaxNumGpmAffCand());
              m_geoAffMrgCtx.maxNumMergeCand = m_geoAffMrgCtx.numValidMergeCand;
+#if JVET_AJ0274_GPM_AFFINE_TM
+            m_geoAffTmMrgCtx = m_geoAffMrgCtx;
+#endif
             }
           }
           if (!pu.affineGPM[0] || !pu.affineGPM[1])
@@ -3064,6 +3073,39 @@ void DecCu::xDeriveCUMV(CodingUnit &cu)
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
           if (pu.geoTmFlag0)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            if (pu.affineGPM[0])
+            {
+              for (int i = 0; i < 3; i++)
+              {
+                m_mvBufBDMVR[0][i].setZero();
+                m_mvBufBDMVR[1][i].setZero();
+              }
+              int uiAffMergeCand = pu.geoMergeIdx0 - m_geoAffTmMrgCtx.m_indexOffset;
+              m_geoAffTmMrgCtx.setAffMergeInfo(pu, pu.geoMergeIdx0);
+              m_pcInterPred->setFillCurTplAboveARMC(false);
+              m_pcInterPred->setBdmvrSubPuMvBuf(m_mvBufBDMVR[0], m_mvBufBDMVR[1]);
+              pu.bdmvrRefine = false;
+              m_pcInterPred->processTM4Affine(pu, m_geoAffTmMrgCtx, 0, false
+#if JVET_AH0119_SUBBLOCK_TM
+                                              , pu.cs->slice->getCheckLDB() ? true : false
+#endif
+#if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE
+                                              , uiAffMergeCand
+#endif
+                                              );
+              pu.cu->affine = false;
+              m_pcInterPred->setFillCurTplAboveARMC(false);
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][0].mv += m_mvBufBDMVR[0][0];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][1].mv += m_mvBufBDMVR[0][1];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][2].mv += m_mvBufBDMVR[0][2];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][0].mv += m_mvBufBDMVR[1][0];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][1].mv += m_mvBufBDMVR[1][1];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][2].mv += m_mvBufBDMVR[1][2];
+            }
+            else
+            {
+#endif
 #if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
             MergeCtx& m_geoTmMrgCtx0 = m_geoTmMrgCtx[GEO_TM_SHAPE_AL];
 #endif
@@ -3130,10 +3172,46 @@ void DecCu::xDeriveCUMV(CodingUnit &cu)
             m_pcInterPred->deriveTMMv(pu);
             m_geoTmMrgCtx0.mvFieldNeighbours[(pu.geoMergeIdx0 << 1)].mv.set(pu.mv[0].getHor(), pu.mv[0].getVer());
             m_geoTmMrgCtx0.mvFieldNeighbours[(pu.geoMergeIdx0 << 1) + 1].mv.set(pu.mv[1].getHor(), pu.mv[1].getVer());
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+            }
 #endif
           }
           if (pu.geoTmFlag1)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            if (pu.affineGPM[1])
+            {
+              for (int i = 0; i < 3; i++)
+              {
+                m_mvBufBDMVR[0][i].setZero();
+                m_mvBufBDMVR[1][i].setZero();
+              }
+              int uiAffMergeCand = pu.geoMergeIdx1 - m_geoAffTmMrgCtx.m_indexOffset;
+              m_geoAffTmMrgCtx.setAffMergeInfo(pu, pu.geoMergeIdx1);
+              m_pcInterPred->setBdmvrSubPuMvBuf(m_mvBufBDMVR[0], m_mvBufBDMVR[1]);
+              pu.bdmvrRefine = false;
+              m_pcInterPred->setFillCurTplAboveARMC(false);
+              m_pcInterPred->processTM4Affine(pu, m_geoAffTmMrgCtx, 0, false
+#if JVET_AH0119_SUBBLOCK_TM
+                                             , pu.cs->slice->getCheckLDB() ? true : false
+#endif
+#if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE
+                                              , uiAffMergeCand
+#endif
+                                              );
+              pu.cu->affine = false;
+              m_pcInterPred->setFillCurTplAboveARMC(false);
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][0].mv += m_mvBufBDMVR[0][0];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][1].mv += m_mvBufBDMVR[0][1];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][2].mv += m_mvBufBDMVR[0][2];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][0].mv += m_mvBufBDMVR[1][0];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][1].mv += m_mvBufBDMVR[1][1];
+              m_geoAffTmMrgCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][2].mv += m_mvBufBDMVR[1][2];
+            }
+            else
+            {
+#endif
 #if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
             MergeCtx& m_geoTmMrgCtx1 = m_geoTmMrgCtx[GEO_TM_SHAPE_AL];
 #endif
@@ -3202,6 +3280,9 @@ void DecCu::xDeriveCUMV(CodingUnit &cu)
             m_geoTmMrgCtx1.mvFieldNeighbours[(pu.geoMergeIdx1 << 1) + 1].mv.set(pu.mv[1].getHor(), pu.mv[1].getVer());
 #endif
           }
+#if JVET_AJ0274_GPM_AFFINE_TM
+          }
+#endif
 #endif
         }
         else
diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h
index c74e55597f0142be3e214b4bc27e46d0a3d2259b..4f8010841ebf1b4ea69bc43da0bc79bd9c1d1d99 100644
--- a/source/Lib/DecoderLib/DecCu.h
+++ b/source/Lib/DecoderLib/DecCu.h
@@ -130,6 +130,9 @@ private:
   MergeCtx          m_geoMrgCtx;
 #if JVET_AG0164_AFFINE_GPM
   AffineMergeCtx    m_geoAffMrgCtx;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  AffineMergeCtx    m_geoAffTmMrgCtx;
+#endif
 #endif
 #if JVET_AI0082_GPM_WITH_INTER_IBC
   Mv                m_geoBvList[GEO_MAX_NUM_IBC_CANDS];
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 285e856913e07830b05a180ba4b8ed8fcc506ab8..f974db44538cd4898d9ee7e5f2a9a49e3424a7e4 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2680,6 +2680,13 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
         READ_UVLC(uiCode, "max_num_aff_merge_cand_minus_max_num_gpm_aff_cand");
         pcSPS->setMaxNumGpmAffCand((uint32_t)(pcSPS->getMaxNumAffineMergeCand() - uiCode));
       }
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (pcSPS->getMaxNumGpmAffCand() > 0)
+      {
+        READ_UVLC(uiCode, "max_num_gpm_aff_tm_cand");
+        pcSPS->setMaxNumGpmAffTmCand((uint32_t)uiCode);
+      }
+#endif
 #endif
 
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_W0097_GPM_MMVD_TM && TM_MRG
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index a3a12b0b42e11c8d2066511f8f7f3f0be5f7d07e..3c5c6027663a50e40b9c1e720e64bdc6c865d5f6 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -5671,6 +5671,9 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
           unary_max_eqprob( candIdx0 - 1, maxNumGeoCand );
         }
         DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.geoMergeIdx0 );
+#if JVET_AJ0274_REGRESSION_GPM_TM
+        m_BinEncoder.encodeBin(pu.geoBlendTmFlag, Ctx::GeoBlendTMFlag());
+#endif
         return;
       }
 #endif
@@ -5787,6 +5790,9 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
       CHECK( pu.gpmInterIbcFlag != (isIbc0 || isIbc1), "gpmInterIbcFlag shall be equal to (isIbc0 || isIbc1)" );
 #endif
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+      bool affGpmTmValid = isAffGPMValid && PU::isAffineGpmTmValid(pu);
+#endif
 
 #if TM_MRG
       if (!pu.geoMMVDFlag0 && !pu.geoMMVDFlag1)
@@ -5794,17 +5800,25 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
 #if JVET_Y0065_GPM_INTRA
         if (!isIntra0 && !isIntra1)
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if ((affGpmTmValid && (pu.affineGPM[0] || pu.affineGPM[1])) || (!pu.affineGPM[0] && !pu.affineGPM[1]))
+#else
 #if JVET_AG0164_AFFINE_GPM
           if( !pu.affineGPM[0] && !pu.affineGPM[1])
+#endif
 #endif
         tm_merge_flag(pu);
         if (pu.tmMergeFlag)
         {
+#if !JVET_AJ0274_GPM_AFFINE_TM
 #if JVET_AG0164_AFFINE_GPM
           CHECK(pu.affineGPM[0] || pu.affineGPM[1], "Affine GPM cannot be used with TM");
+#endif
 #endif
           CHECK(!pu.geoTmFlag0 || !pu.geoTmFlag1, "both must be true");
+#if !JVET_AJ0274_GPM_AFFINE_TM
           CHECK(pu.geoMergeIdx0 == pu.geoMergeIdx1, "Incorrect geoMergeIdx0 and geoMergeIdx1");
+#endif
           geo_merge_idx(pu);
         }
         else
@@ -6293,6 +6307,12 @@ void CABACWriter::geo_merge_idx(const PredictionUnit& pu)
 #endif
 #if JVET_AG0164_AFFINE_GPM
   int maxNumGeoCand = pu.affineGPM[0] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[0] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
 #else
   const int maxNumGeoCand = pu.cs->sps->getMaxNumGeoCand();
 #endif
@@ -6322,6 +6342,12 @@ void CABACWriter::geo_merge_idx(const PredictionUnit& pu)
 
 #if JVET_AG0164_AFFINE_GPM
   maxNumGeoCand = pu.affineGPM[1] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[1] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
   numCandminus2 = maxNumGeoCand - 2;
 #endif
   if (numCandminus2 > 0
@@ -6394,6 +6420,12 @@ void CABACWriter::geo_merge_idx1(const PredictionUnit& pu)
 
 #if JVET_AG0164_AFFINE_GPM
   int maxNumGeoCand = pu.affineGPM[0] ? pu.cs->sps->getMaxNumGpmAffCand(): pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[0] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
 #else
   const int maxNumGeoCand = pu.cs->sps->getMaxNumGeoCand();
 #endif
@@ -6467,6 +6499,12 @@ void CABACWriter::geo_merge_idx1(const PredictionUnit& pu)
 
 #if JVET_AG0164_AFFINE_GPM
   maxNumGeoCand = pu.affineGPM[1] ? pu.cs->sps->getMaxNumGpmAffCand() : pu.cs->sps->getMaxNumGeoCand();
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (pu.affineGPM[1] && pu.tmMergeFlag)
+  {
+    maxNumGeoCand = pu.cs->sps->getMaxNumGpmAffTmCand();
+  }
+#endif
   numCandminus2 = maxNumGeoCand - 2;
 #endif
 
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index a399a22add3fc1b162a4a0e474c017e22ce6c5b7..616369020a22ab7bf9eddaa436d81378558df2ae 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -968,6 +968,9 @@ protected:
   uint32_t      m_maxNumGeoCand;
 #if JVET_AG0164_AFFINE_GPM
   uint32_t      m_maxNumGpmAffCand;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  uint32_t      m_maxNumGpmAffTmCand;
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
   uint32_t      m_maxNumMHPCand;
@@ -2675,6 +2678,10 @@ public:
 #if JVET_AG0164_AFFINE_GPM
   void         setMaxNumGpmAffCand(uint32_t u)                       { m_maxNumGpmAffCand = u; }
   uint32_t     getMaxNumGpmAffCand()                                 { return m_maxNumGpmAffCand; }
+#if JVET_AJ0274_GPM_AFFINE_TM
+  void         setMaxNumGpmAffTmCand(uint32_t u)                     { m_maxNumGpmAffTmCand = u; }
+  uint32_t     getMaxNumGpmAffTmCand()                               { return m_maxNumGpmAffTmCand; }
+#endif
 #endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
   void         setMaxNumMHPCand                  ( uint32_t u )      { m_maxNumMHPCand = u;    }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 01bdfccc3ed57b650c748fb9b21abb7c883a21ef..4b27948fbd737786ae9a2356c6f0043142b9d13e 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -104,6 +104,9 @@ EncCu::EncCu() : m_GeoModeTest
 #if JVET_W0097_GPM_MMVD_TM
   m_fastGpmMmvdSearch = false;
   m_fastGpmMmvdRelatedCU = false;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  m_fastGpmAffSearch = 0x00;
+#endif
   m_includeMoreMMVDCandFirstPass = false;
   m_maxNumGPMDirFirstPass = 64;
   m_numCandPerPar = 5;
@@ -342,6 +345,9 @@ void EncCu::create( EncCfg* encCfg )
     m_fastGpmMmvdRelatedCU = ((encCfg->getIntraPeriod() < 0) && ((sourceWidth * sourceHeight) >= (1280 * 720))) && !encCfg->getIBCMode();
   }
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+  m_fastGpmAffSearch = encCfg->getIntraPeriod() < 0 ? (sourceWidth * sourceHeight <= 832 * 480 ? 0x01 : 0x03) : (sourceWidth * sourceHeight >= 3840 * 2160 ? 0x02 : 0x04);
+#endif
 
   m_includeMoreMMVDCandFirstPass = ((encCfg->getIntraPeriod() > 0) || ((encCfg->getIntraPeriod() < 0) && m_fastGpmMmvdSearch));
   m_maxNumGPMDirFirstPass = ((encCfg->getIntraPeriod() < 0) ? 50 : (m_fastGpmMmvdSearch ? 36 : 64));
@@ -351,6 +357,9 @@ void EncCu::create( EncCfg* encCfg )
   {
     m_acGeoMergeTmpBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight));
     m_acGeoSADTmpBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight));
+#if JVET_AJ0274_REGRESSION_GPM_TM
+    m_acGeoBlendTMBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight));
+#endif
   }
 #endif
 #endif
@@ -551,6 +560,9 @@ void EncCu::destroy()
   {
     m_acGeoMergeTmpBuffer[ui].destroy();
     m_acGeoSADTmpBuffer[ui].destroy();
+#if JVET_AJ0274_REGRESSION_GPM_TM
+    m_acGeoBlendTMBuffer[ui].destroy();
+#endif
   }
 #endif
 #endif
@@ -9850,6 +9862,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
   MergeCtx& mergeCtxRegular = mergeCtx;
 #endif
+#endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  MergeCtx geoBlendTmCtx;
 #endif
   const SPS &sps = *tempCS->sps;
   CodedCUInfo& relatedCU = ((EncModeCtrlMTnoRQT *)m_modeCtrl)->getBlkInfo(pm.currArea());
@@ -9865,7 +9880,13 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       for (int j = 0; j < SUB_TMVP_NUM; j++)
       {
         mergeCtx[i].subPuMvpMiBuf[j] = MotionBuf(m_subPuMiBuf[j], bufSize);
-    }
+#if JVET_AJ0274_REGRESSION_GPM_TM
+        if (i == 0)
+        {
+          geoBlendTmCtx.subPuMvpMiBuf[j] = MotionBuf(m_subPuMiBuf[j], bufSize);
+        }
+#endif
+      }
 #else
       mergeCtx[i].subPuMvpMiBuf = MotionBuf(m_subPuMiBuf, bufSize);
 #endif
@@ -9878,8 +9899,17 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AE0046_BI_GPM
   std::array<bool, GEO_MAX_NUM_UNI_CANDS> refinePossible;
   refinePossible.fill(false);
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  std::array<bool, GEO_MAX_NUM_UNI_CANDS> refinePossibleTM;
+  refinePossibleTM.fill(false);
+#endif
 #endif
 
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  int isGeoTmMCAvail[GEO_TM_MAX_NUM_CANDS];
+  std::memset(isGeoTmMCAvail, 0, GEO_TM_MAX_NUM_CANDS * sizeof(int));
+  PelUnitBuf geoTmBuffer[GEO_TM_MAX_NUM_CANDS];
+#endif
 #if JVET_AI0082_GPM_WITH_INTER_IBC
   bool testGeoInterIbc = sps.getUseGeoInterIbc();
 #endif
@@ -9905,6 +9935,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
 #if JVET_AG0164_AFFINE_GPM
   double geoAffMergeIdxCost[GEO_MAX_NUM_UNI_AFF_CANDS];
+#if JVET_AJ0274_GPM_AFFINE_TM
+  double geoAffTmMergeIdxCost[GEO_AFF_TM_MAX_AFF_CANDS];
+#endif
   uint8_t maxNumGpmAffMergeCandidates = tempCS->sps->getMaxNumGpmAffCand();
   CHECK(maxNumGpmAffMergeCandidates > GEO_MAX_NUM_UNI_AFF_CANDS, "Maximum GPM Affine Num is too large");
 #endif
@@ -9935,6 +9968,17 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
     uint64_t fracBits = m_CABACEstimator->geo_mergeIdx_est(ctxStart, idx, maxNumGpmAffMergeCandidates, 1);
     geoAffMergeIdxCost[idx] = (double)fracBits * sqrtLambdaFracBits;
   }
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+  int numAffTmAffCands = tempCS->sps->getMaxNumGpmAffTmCand();
+  if (numAffTmAffCands > 0)
+  {
+    for (int idx = 0; idx < numAffTmAffCands; idx++)
+    {
+      uint64_t fracBits = m_CABACEstimator->geo_mergeIdx_est(ctxStart, idx, numAffTmAffCands, 1);
+      geoAffTmMergeIdxCost[idx] = (double)fracBits * sqrtLambdaFracBits;
+    }
+  }
 #endif
   for (int idx = 0; idx < 2; idx++)
   {
@@ -10044,6 +10088,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_X0049_ADAPT_DMVR
   pu.bmMergeFlag = false;
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  pu.geoBlendTmFlag = false;
+#endif
 
 #if JVET_AG0164_AFFINE_GPM
   double geoAffineFlagCost[2] = { 0.0, 0.0 };
@@ -10058,6 +10105,10 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
   }
 
   bool affGPMValid = PU::isAffineGPMValid(pu);
+#if JVET_AJ0274_GPM_AFFINE_TM
+  bool affGpmTmValid = affGPMValid && PU::isAffineGpmTmValid(pu);
+  affGpmTmValid &= (pu.lx() > 0 || pu.ly() > 0);
+#endif
 
   pu.affineGPM[0]= pu.affineGPM[1] = 0;
   if (!affGPMValid)
@@ -10121,6 +10172,13 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 
       if (!isSecondPass)
       {
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (pu.cs->sps->getMaxNumGpmAffTmCand() > 0 && (m_fastGpmAffSearch & 0x01))
+        {
+          numSATDCands += 1;
+        }
+        else
+#endif
         numSATDCands += affMergeCtx.numValidMergeCand + 1;
       }
     }
@@ -10130,6 +10188,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 
     affMergeCtx.m_indexOffset = numRegularGpmMergeCand;
   }
+#if JVET_AJ0274_GPM_AFFINE_TM
+  AffineMergeCtx affTmMergeCtx = affMergeCtx;
+#endif
 
   PelUnitBuf geoBuffer[GEO_MAX_ALL_INTER_UNI_CANDS];
   PelUnitBuf geoTempBuf[GEO_MAX_ALL_INTER_UNI_CANDS];
@@ -10224,7 +10285,12 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
 #endif
 #if TM_MRG
+#if JVET_AJ0274_GPM_AFFINE_TM
+  uint8_t isGeoTmChromaAvail[GEO_TM_MAX_NUM_CANDS];
+  memset(isGeoTmChromaAvail, 0, sizeof(uint8_t) * GEO_TM_MAX_NUM_CANDS);
+#else
   bool isGeoTmChromaAvail[GEO_TM_MAX_NUM_CANDS];
+#endif
   memset(isGeoTmChromaAvail, false, sizeof(bool) * GEO_TM_MAX_NUM_CANDS);
 #endif
 
@@ -10981,7 +11047,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         if (sps.getUseGPMTMMode() 
 
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+          && ((sps.getMaxNumGpmAffTmCand() > 0) || (sps.getMaxNumGpmAffTmCand() <= 0 && !isAffine0 && !isAffine1))
+#else
           && (!isAffine0 && !isAffine1)
+#endif
           && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS&& mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS
 #else
 #if JVET_Y0065_GPM_INTRA
@@ -11229,7 +11299,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         && !isIntra0 && !isIntra1
 #endif
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+        && ((sps.getMaxNumGpmAffTmCand() > 0) || (sps.getMaxNumGpmAffTmCand() <= 0 && !isAffine0 && !isAffine1))
+#else
         && ( !isAffine0 && !isAffine1)
+#endif
 #endif
         )
 #else
@@ -11912,6 +11986,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       pu.geoSplitDir = geoSplitDirList[candidateIdx];
       pu.geoMergeIdx0 = geoMergeCand0[candidateIdx];
       pu.geoMergeIdx1 = geoMergeCand1[candidateIdx];
+#if JVET_AJ0274_REGRESSION_GPM_TM
+      pu.geoBlendTmFlag = false;
+#endif
 #if JVET_AE0046_BI_GPM
       PU::setGpmDirMode(pu);
 #endif
@@ -12045,6 +12122,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF]
 #if JVET_AG0164_AFFINE_GPM
         , affMergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+        , affTmMergeCtx
+#endif
 #endif
         , *mergeTmCtx0, *mergeTmCtx1, pu.geoSplitDir, pu.geoMergeIdx0, pu.geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, pu.geoBldIdx, m_pcIntraSearch->m_intraMPM,
 #if JVET_AI0082_GPM_WITH_INTER_IBC
@@ -12103,17 +12183,46 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 
   CodingUnit *bestCU = bestCS->getCU(CHANNEL_TYPE_LUMA);
   bool skipGPMMMVD = false;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  bool skipGpmMmvdButNotTm = false;
+#endif
   if (geoNumMrgSATDCand > 0)
   {
     if (bestCU->skip && !bestCU->geoFlag && !bestCU->affine && !bestCU->mmvdSkip && !bestCU->firstPU->mmvdMergeFlag)
     {
       skipGPMMMVD = true;
     }
+#if JVET_AJ0274_REGRESSION_GPM_TM
+    else if (m_pcEncCfg->getIntraPeriod() > 0 && bestCU->affine && bestCU->skip)
+    {
+      skipGPMMMVD = true;
+    }
+#endif
     else if (bestCU->affine && bestCU->skip && (bestCU->lwidth() >= 16 || bestCU->lheight() >= 16))
     {
       skipGPMMMVD = true;
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (!isSecondPass && m_fastGpmAffSearch >= 0x02)
+      {
+        skipGpmMmvdButNotTm = true;
+      }
+#endif
+    }
+  }
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  bool skipGPMTM = false;
+  if (geoNumMrgSATDCand > 0 && cu.slice->getCheckLDC() && m_pcEncCfg->getIntraPeriod() > 0)
+  {
+    if (bestCU->geoFlag && bestCU->firstPU->gpmIntraFlag)
+    {
+      skipGPMTM = true;
+    }
+    else if (!bestCU->skip && !bestCU->firstPU->mmvdMergeFlag && !bestCU->firstPU->tmMergeFlag && !bestCU->geoFlag)
+    {
+      skipGPMTM = true;
     }
   }
+#endif
 #if JVET_AG0164_AFFINE_GPM
   bool isBaseMergeCandIncluded[GEO_MAX_ALL_INTER_UNI_CANDS];
   std::memset(isBaseMergeCandIncluded, false, GEO_MAX_ALL_INTER_UNI_CANDS * sizeof(bool));
@@ -12128,6 +12237,12 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
   {
     skipGPMMMVD = (selGeoModeRDList[0] > (bestNormalMrgCost * 1.1));
   }
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (skipGPMMMVD && skipGpmMmvdButNotTm)
+  {
+    skipGPMMMVD = false;
+  }
+#endif
 
   if (!skipGPMMMVD)
   {
@@ -12267,6 +12382,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AG0164_AFFINE_GPM
     pu.affineGPM[0] = pu.affineGPM[1] = 0;
 #endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+    pu.geoBlendTmFlag = false;
+#endif
 
     bool simpleGPMMMVDStep = (m_pcEncCfg->getIntraPeriod() == -1);
 #if JVET_AG0164_AFFINE_GPM
@@ -12275,7 +12393,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
     double mmvdMrgCost[GEO_MAX_NUM_UNI_CANDS][GPM_EXT_MMVD_MAX_REFINE_NUM];
 #endif
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+    for (uint8_t mergeCand = 0; mergeCand < (skipGpmMmvdButNotTm ? 0 : numRegularGpmMergeCand); mergeCand++)
+#else
     for (uint8_t mergeCand = 0; mergeCand < numRegularGpmMergeCand; mergeCand++)
+#endif
 #else
     for (uint8_t mergeCand = 0; mergeCand < maxNumMergeCandidates; mergeCand++)
 #endif
@@ -12374,7 +12496,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         sadMask = &g_geoEncSadMask[g_angle2mask[g_geoParams[splitDir][0]]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
       }
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+      for (uint8_t mergeCand = 0; mergeCand < (skipGpmMmvdButNotTm ? 0 : numRegularGpmMergeCand); mergeCand++)
+#else
       for (uint8_t mergeCand = 0; mergeCand < numRegularGpmMergeCand; mergeCand++)
+#endif
 #else
       for (uint8_t mergeCand = 0; mergeCand < maxNumMergeCandidates; mergeCand++)	  
 #endif
@@ -12426,6 +12552,10 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       }
     }
 
+#if JVET_AJ0274_GPM_AFFINE_TM
+    if (!skipGpmMmvdButNotTm)
+    {
+#endif
     for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
     {
 #if JVET_Y0065_GPM_INTRA
@@ -12516,7 +12646,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           if (sps.getUseGPMTMMode() 
 #if JVET_AG0164_AFFINE_GPM
             && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS && mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS
+#if JVET_AJ0274_GPM_AFFINE_TM
+            && ((sps.getMaxNumGpmAffTmCand() > 0) || (sps.getMaxNumGpmAffTmCand() <= 0 && !isAffine0 && !isAffine1))
+#else
             && !isAffine0 && !isAffine1
+#endif
 #else
 #if JVET_Y0065_GPM_INTRA
             && mergeCand0 < GEO_MAX_NUM_UNI_CANDS && mergeCand1 < GEO_MAX_NUM_UNI_CANDS
@@ -12539,6 +12673,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         }
       }
     }
+#if JVET_AJ0274_GPM_AFFINE_TM
+    }
+#endif
 #if JVET_AG0164_AFFINE_GPM
     pu.affineGPM[0] = 0;
     pu.affineGPM[1] = 0;
@@ -12549,7 +12686,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #else
     uint8_t maxNumTmMrgCand = maxNumMergeCandidates;
 #endif
+#if !JVET_AJ0274_REGRESSION_GPM_TM
     PelUnitBuf geoTmBuffer[GEO_TM_MAX_NUM_CANDS];
+#endif
     PelUnitBuf geoTmTempBuf[GEO_TM_MAX_NUM_CANDS];
 #if JVET_AE0046_BI_GPM
     bool tmRefinePossible[GEO_TM_MAX_NUM_CANDS];
@@ -12562,6 +12701,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
     if (sps.getUseGPMTMMode()
 #if JVET_Y0065_GPM_INTRA
       && !bUseOnlyOneVector
+#endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+      && !skipGPMTM
 #endif
       )
 #else
@@ -12659,9 +12801,66 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           distParamWholeBlk.cur.buf = geoTmTempBuf[mergeCand].Y().buf;
           distParamWholeBlk.cur.stride = geoTmTempBuf[mergeCand].Y().stride;
           sadTmWholeBlk[mergeCand] = distParamWholeBlk.distFunc(distParamWholeBlk);
+#if JVET_AJ0274_REGRESSION_GPM_TM
+          if (tmType == GEO_TM_SHAPE_AL)
+          {
+            isGeoTmMCAvail[mergeCand] = 1;
+          }
+#endif
         }
       }
       pu.tmMergeFlag = false;
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (affGpmTmValid)
+      {
+        if ((CU::isInter(*bestCU)) && bestCU->firstPU->interDir == 3)
+        {
+          numAffTmAffCands -= ((m_fastGpmAffSearch & 0x01) ? (numAffTmAffCands -= m_fastGpmAffSearch) : (m_fastGpmAffSearch <= 0x02 ? 3 : 2));
+          numAffTmAffCands -= (isSecondPass && (m_fastGpmAffSearch & 0x01) == 0) ? 2 : 0;
+        }
+#if JVET_AH0119_SUBBLOCK_TM
+        EAffineModel affType[AFFINE_MRG_MAX_NUM_CANDS];
+#endif
+        m_pcInterSearch->setFillCurTplAboveARMC(false);
+        for (uint8_t mrgIdx = numRegularGpmMergeCand; mrgIdx < numRegularGpmMergeCand + numAffTmAffCands; mrgIdx++)
+        {
+          uint8_t uiAffMergeCand = mrgIdx - numRegularGpmMergeCand;
+          uint8_t mergeCand = uiAffMergeCand + 3 * GEO_MAX_NUM_UNI_CANDS;
+          affTmMergeCtx.setAffMergeInfo(pu, mrgIdx);
+          m_pcInterSearch->processTM4Affine(pu, affTmMergeCtx, uiAffMergeCand, true
+#if JVET_AH0119_SUBBLOCK_TM
+                                            , pu.cs->slice->getCheckLDB() ? true : false
+#endif
+#if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE
+                                            , uiAffMergeCand
+#endif
+                                            );
+#if JVET_AH0119_SUBBLOCK_TM
+          affType[uiAffMergeCand] = (EAffineModel)pu.cu->affineType;
+#endif
+          affTmMergeCtx.affineType[uiAffMergeCand]= affType[uiAffMergeCand];
+
+          affTmMergeCtx.setAffMergeInfo(pu, mrgIdx);
+          if (m_pcEncCfg->getMCTSEncConstraint() && (!(MCTSHelper::checkMvBufferForMCTSConstraint(pu))))
+          {
+            tempCS->initStructData(encTestMode.qp);
+            return;
+          }
+          geoTmBuffer[mergeCand] = m_acGeoMergeTmpBuffer[mergeCand].getBuf(localUnitArea);
+          m_pcInterSearch->motionCompensation(pu, geoTmBuffer[mergeCand], REF_PIC_LIST_X, true, false);
+          pu.cu->affine = false;
+
+          // calculate SAD for each candidate
+          geoTmTempBuf[mergeCand] = m_acGeoSADTmpBuffer[mergeCand].getBuf(localUnitArea);
+          geoTmTempBuf[mergeCand].Y().copyFrom(geoTmBuffer[mergeCand].Y());
+          geoTmTempBuf[mergeCand].Y().roundToOutputBitdepth(geoTmTempBuf[mergeCand].Y(), cu.slice->clpRng(COMPONENT_Y));
+          distParamWholeBlk.cur.buf = geoTmTempBuf[mergeCand].Y().buf;
+          distParamWholeBlk.cur.stride = geoTmTempBuf[mergeCand].Y().stride;
+          sadTmWholeBlk[mergeCand] = distParamWholeBlk.distFunc(distParamWholeBlk);
+        }
+        m_pcInterSearch->setFillCurTplAboveARMC(false);
+      }
+#endif
 
       for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
       {
@@ -12687,12 +12886,20 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           maskStride2 = -(int)cu.lwidth();
           sadMask = &g_geoEncSadMask[g_angle2mask[g_geoParams[splitDir][0]]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
         }
+#if JVET_AJ0274_GPM_AFFINE_TM
+        for (uint8_t mergeCand = 0; mergeCand < (affGpmTmValid ? maxNumTmMrgCand + numAffTmAffCands : maxNumTmMrgCand); mergeCand++)
+#else
         for (uint8_t mergeCand = 0; mergeCand < maxNumTmMrgCand; mergeCand++)
+#endif
         {
           if (mrgDuplicated[mergeCand])
           {
             continue;
           }
+#if JVET_AJ0274_GPM_AFFINE_TM
+          if (mergeCand < maxNumTmMrgCand)
+          {
+#endif
 
           uint8_t mergeCand0 = mergeCand + (g_geoTmShape[0][g_geoParams[splitDir][0]] - 1) * GEO_MAX_NUM_UNI_CANDS;
           m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), geoTmTempBuf[mergeCand0].Y().buf, geoTmTempBuf[mergeCand0].Y().stride, sadMask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
@@ -12705,18 +12912,41 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           sadSmall = sadTmWholeBlk[mergeCand1] - distParam.distFunc(distParam);
           tempCost = (double)sadSmall + geoMergeIdxCost[mergeCand] + geoMMVDFlagCost[0];
           m_geoMMVDCostList.insert(splitDir, 1, mergeCand, (GPM_EXT_MMVD_MAX_REFINE_NUM + 1), tempCost);
+#if JVET_AJ0274_GPM_AFFINE_TM
+          }
+          else
+          {
+            uint8_t mergeCand0 = mergeCand - maxNumTmMrgCand + 3 * GEO_MAX_NUM_UNI_CANDS;
+            m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), geoTmTempBuf[mergeCand0].Y().buf, geoTmTempBuf[mergeCand0].Y().stride, sadMask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+            sadLarge = distParam.distFunc(distParam);
+            double tempCost = (double)sadLarge + geoAffTmMergeIdxCost[mergeCand - maxNumTmMrgCand] + geoMMVDFlagCost[0];
+            m_geoMMVDCostList.insert(splitDir, 0, mergeCand, (GPM_EXT_MMVD_MAX_REFINE_NUM + 1), tempCost);
+
+            sadSmall = sadTmWholeBlk[mergeCand0] - sadLarge;
+            tempCost = (double)sadSmall + geoAffTmMergeIdxCost[mergeCand - maxNumTmMrgCand] + geoMMVDFlagCost[0];
+            m_geoMMVDCostList.insert(splitDir, 1, mergeCand, (GPM_EXT_MMVD_MAX_REFINE_NUM + 1), tempCost);
+          }
+#endif
         }
       }
 
       for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
       {
+#if JVET_AJ0274_GPM_AFFINE_TM
+        for (int mergeCand0 = 0; mergeCand0 < (affGpmTmValid ? maxNumTmMrgCand + numAffTmAffCands : maxNumTmMrgCand); mergeCand0++)
+#else
         for (int mergeCand0 = 0; mergeCand0 < maxNumTmMrgCand; mergeCand0++)
+#endif
         {
           if (mrgDuplicated[mergeCand0])
           {
             continue;
           }
+#if JVET_AJ0274_GPM_AFFINE_TM
+          for (int mergeCand1 = 0; mergeCand1 < (affGpmTmValid ? maxNumTmMrgCand + numAffTmAffCands : maxNumTmMrgCand); mergeCand1++)
+#else
           for (int mergeCand1 = 0; mergeCand1 < maxNumTmMrgCand; mergeCand1++)
+#endif
           {
             if (mrgDuplicated[mergeCand1])
             {
@@ -12726,13 +12956,24 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
             {
               continue;
             }
+#if JVET_AJ0274_GPM_AFFINE_TM
+            int isAffine0 = (mergeCand0 >= numRegularGpmMergeCand && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+            int isAffine1 = (mergeCand1 >= numRegularGpmMergeCand && mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+            pu.affineGPM[0] = isAffine0;
+            pu.affineGPM[1] = isAffine1;
+#endif
 
 #if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
             int geoSyntaxMode = std::numeric_limits<uint8_t>::max();
             if(sps.getUseAltGPMSplitModeCode())
             {
+#if JVET_AJ0274_GPM_AFFINE_TM
+              m_pcInterSearch->setGeoTMSplitModeToSyntaxTable(pu, mergeCtx, affTmMergeCtx, mergeCand0, mergeCand1, tmMmvdBufIdx0 - 1, tmMmvdBufIdx1 - 1);
+              geoSyntaxMode = m_pcInterSearch->convertGeoSplitModeToSyntax(splitDir, mergeCand0, mergeCand1, tmMmvdBufIdx0 - 1, tmMmvdBufIdx1 - 1);
+#else
               m_pcInterSearch->setGeoTMSplitModeToSyntaxTable(pu, mergeCtx, mergeCand0, mergeCand1, tmMmvdBufIdx0 - 1, tmMmvdBufIdx1 - 1);
               geoSyntaxMode = m_pcInterSearch->convertGeoSplitModeToSyntax(splitDir, mergeCand0, mergeCand1, tmMmvdBufIdx0 - 1, tmMmvdBufIdx1 - 1);
+#endif
               if (geoSyntaxMode == std::numeric_limits<uint8_t>::max())
               {
                 continue;
@@ -12755,6 +12996,10 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       }
     }
 #endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+    pu.affineGPM[0] = 0;
+    pu.affineGPM[1] = 0;
+#endif
 
     int numberGeoCandChecked = (int)geoSADCostList.size();
     if (numberGeoCandChecked == 0)
@@ -12775,6 +13020,10 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       int splitDir = geoSplitDirList[candidateIdx];
       int mergeCand0 = geoMergeCand0[candidateIdx];
       int mergeCand1 = geoMergeCand1[candidateIdx];
+#if JVET_AJ0274_GPM_AFFINE_TM
+      int isAffine0 = (mergeCand0 >= numRegularGpmMergeCand && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+      int isAffine1 = (mergeCand1 >= numRegularGpmMergeCand && mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+#endif
 #if TM_MRG
       bool tmFlag0 = (geoMmvdCand0[candidateIdx] == (GPM_EXT_MMVD_MAX_REFINE_NUM + 1));
       bool tmFlag1 = (geoMmvdCand1[candidateIdx] == (GPM_EXT_MMVD_MAX_REFINE_NUM + 1));
@@ -12804,8 +13053,10 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       }
 #endif
 #if JVET_AG0164_AFFINE_GPM                          
+#if !JVET_AJ0274_GPM_AFFINE_TM
       int isAffine0 = (mergeCand0 >= numRegularGpmMergeCand && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS && !tmFlag0) ? 1 : 0;
       int isAffine1 = (mergeCand1 >= numRegularGpmMergeCand && mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS && !tmFlag1) ? 1 : 0;
+#endif
       pu.affineGPM[0] = isAffine0;
       pu.affineGPM[1] = isAffine1;
       CHECK(mmvdFlag0&& isAffine0, "Aff GPM MMVD is not allowed");
@@ -12969,7 +13220,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if TM_MRG 
           if (tmFlag0)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            int mrgTmCand0 = isAffine0 ? (mergeCand0 - numRegularGpmMergeCand + 3 * GEO_MAX_NUM_UNI_CANDS) : (mergeCand0 + (g_geoTmShape[0][g_geoParams[splitDir][0]] - 1) * GEO_MAX_NUM_UNI_CANDS);
+#else
             int mrgTmCand0 = mergeCand0 + (g_geoTmShape[0][g_geoParams[splitDir][0]] - 1) * GEO_MAX_NUM_UNI_CANDS;
+#endif
             predSrc0 = geoTmBuffer[mrgTmCand0];
           }
           else if (mmvdFlag0)
@@ -12983,7 +13238,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 
           if (tmFlag1)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            int mrgTmCand1 = isAffine1 ? (mergeCand1 - numRegularGpmMergeCand + 3 * GEO_MAX_NUM_UNI_CANDS) : (mergeCand1 + (g_geoTmShape[1][g_geoParams[splitDir][0]] - 1) * GEO_MAX_NUM_UNI_CANDS);
+#else
             int mrgTmCand1 = mergeCand1 + (g_geoTmShape[1][g_geoParams[splitDir][0]] - 1) * GEO_MAX_NUM_UNI_CANDS;
+#endif
             predSrc1 = geoTmBuffer[mrgTmCand1];
           }
           else if (mmvdFlag1)
@@ -13033,7 +13292,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         {
           updateCost += geoIntraFlag0Cost[isIntra0];
         }
+#if JVET_AJ0274_GPM_AFFINE_TM
+        updateCost += (isIntra0 ? geoIntraIdxCost[intraIdx0] : (isAffine0 ? (tmFlag0 ? geoAffTmMergeIdxCost[mergeCand0 - numRegularGpmMergeCand] : geoAffMergeIdxCost[mergeCand0 - numRegularGpmMergeCand]) : geoMergeIdxCost[mergeCand0]));
+#else
         updateCost += (isIntra0 ? geoIntraIdxCost[intraIdx0] : (isAffine0 ? geoAffMergeIdxCost[mergeCand0 - numRegularGpmMergeCand] : geoMergeIdxCost[mergeCand0]));
+#endif
         if (!bUseOnlyOneVector || isIntra0)
         {
           if (mmvdFlag1)
@@ -13044,7 +13307,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           {
             updateCost += geoIntraFlag1Cost[isIntra0][isIntra1];
           }
+#if JVET_AJ0274_GPM_AFFINE_TM
+          updateCost += (isIntra1 ? geoIntraIdxCost[intraIdx1] : (isAffine1 ? (tmFlag1 ? geoAffTmMergeIdxCost[mergeCand1 - numRegularGpmMergeCand] : geoAffMergeIdxCost[mergeCand1 - numRegularGpmMergeCand]) : geoMergeIdxCost[mergeCand1]));
+#else
           updateCost += (isIntra1 ? geoIntraIdxCost[intraIdx1] : (isAffine1 ? geoAffMergeIdxCost[mergeCand1 - numRegularGpmMergeCand] : geoMergeIdxCost[mergeCand1]));
+#endif
         }
 #else
         double updateCost =
@@ -13086,7 +13353,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_Y0065_GPM_INTRA
           if (!mmvdFlag0 && !mmvdFlag1 && !isIntra0 && !isIntra1
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+            && ((sps.getMaxNumGpmAffTmCand() > 0) || (sps.getMaxNumGpmAffTmCand() <= 0 && !isAffine0 && !isAffine1))
+#else
             && !isAffine0 && !isAffine1
+#endif
 #endif
             )
 #else
@@ -13335,8 +13606,13 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       bool tmFlag1 = (geoMmvdCand1[candidateIdx] == (GPM_EXT_MMVD_MAX_REFINE_NUM + 1));
       bool mmvdFlag0 = (geoMmvdCand0[candidateIdx] >= 1 && geoMmvdCand0[candidateIdx] <= GPM_EXT_MMVD_MAX_REFINE_NUM);
       bool mmvdFlag1 = (geoMmvdCand1[candidateIdx] >= 1 && geoMmvdCand1[candidateIdx] <= GPM_EXT_MMVD_MAX_REFINE_NUM);
+#if JVET_AJ0274_GPM_AFFINE_TM
+      int  mmvdCand0 = (mmvdFlag0 ? (geoMmvdCand0[candidateIdx] - 1) : -1);
+      int  mmvdCand1 = (mmvdFlag1 ? (geoMmvdCand1[candidateIdx] - 1) : -1);
+#else
       int  mmvdCand0 = (mmvdFlag0 ? (geoMmvdCand0[candidateIdx] - 1) : MAX_INT);
       int  mmvdCand1 = (mmvdFlag1 ? (geoMmvdCand1[candidateIdx] - 1) : MAX_INT);
+#endif
       int mrgTmCand0 = MAX_INT, mrgTmCand1 = MAX_INT;
 #else
       int mmvdCand0 = geoMmvdCand0[candidateIdx] - 1;
@@ -13349,13 +13625,20 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AG0164_AFFINE_GPM
       int isIntra0 = (mergeCand0 >= GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
       int isIntra1 = (mergeCand1 >= GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+#if JVET_AJ0274_GPM_AFFINE_TM
+      int isAffine0 = (mergeCand0 >= numRegularGpmMergeCand && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+      int isAffine1 = (mergeCand1 >= numRegularGpmMergeCand && mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS) ? 1 : 0;
+#else
       int isAffine0 = (mergeCand0 >= numRegularGpmMergeCand && mergeCand0 < GEO_MAX_ALL_INTER_UNI_CANDS && !tmFlag0) ? 1 : 0;
       int isAffine1 = (mergeCand1 >= numRegularGpmMergeCand && mergeCand1 < GEO_MAX_ALL_INTER_UNI_CANDS && !tmFlag1) ? 1 : 0;
+#endif
 
       pu.affineGPM[0] = isAffine0;
       pu.affineGPM[1] = isAffine1;
+#if !JVET_AJ0274_GPM_AFFINE_TM
       CHECK(isAffine0 && tmFlag0, "GPM affine cannot be used together with GPM TM");
       CHECK(isAffine1 && tmFlag1, "GPM affine cannot be used together with GPM TM");
+#endif
 #else
       int isIntra0 = (mergeCand0 >= GEO_MAX_NUM_UNI_CANDS) ? 1 : 0;
       int isIntra1 = (mergeCand1 >= GEO_MAX_NUM_UNI_CANDS) ? 1 : 0;
@@ -13422,6 +13705,29 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if TM_MRG
       else if (tmFlag0)
       {
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (isAffine0)
+        {
+          mrgTmCand0 = mergeCand0 - numRegularGpmMergeCand + 3 * GEO_MAX_NUM_UNI_CANDS;
+          if (isChromaEnabled(pu.chromaFormat) && !isGeoTmChromaAvail[mrgTmCand0])
+          {
+            affTmMergeCtx.setAffMergeInfo(pu, mergeCand0);
+            if (pu.refIdx[0] >= 0)
+            {
+              PU::setAllAffineMv(pu, pu.mvAffi[0][0], pu.mvAffi[0][1], pu.mvAffi[0][2], REF_PIC_LIST_0);
+            }
+            if (pu.refIdx[1] >= 0)
+            {
+              PU::setAllAffineMv(pu, pu.mvAffi[1][0], pu.mvAffi[1][1], pu.mvAffi[1][2], REF_PIC_LIST_1);
+            }
+            m_pcInterSearch->motionCompensation(pu, geoTmBuffer[mrgTmCand0], REF_PIC_LIST_X, false, true);
+            pu.cu->affine = false;
+            isGeoTmChromaAvail[mrgTmCand0] = 1;
+          }
+        }
+        else
+        {
+#endif
         int geoTmType = g_geoTmShape[0][g_geoParams[splitDir][0]];
         mrgTmCand0 = mergeCand0 + (geoTmType - 1) * GEO_MAX_NUM_UNI_CANDS;
         if (isChromaEnabled(pu.chromaFormat) && !isGeoTmChromaAvail[mrgTmCand0])
@@ -13447,6 +13753,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           m_pcInterSearch->setLumaBdofReady(false);
 #endif
         }
+#if JVET_AJ0274_GPM_AFFINE_TM
+        }
+#endif
       }
 #endif
 #if JVET_AG0164_AFFINE_GPM
@@ -13577,6 +13886,29 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if TM_MRG
       else if (tmFlag1)
       {
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (isAffine1)
+        {
+          mrgTmCand1 = mergeCand1 - numRegularGpmMergeCand + 3 * GEO_MAX_NUM_UNI_CANDS;
+          if (isChromaEnabled(pu.chromaFormat) && !isGeoTmChromaAvail[mrgTmCand1])
+          {
+            affTmMergeCtx.setAffMergeInfo(pu, mergeCand1);
+            if (pu.refIdx[0] >= 0)
+            {
+              PU::setAllAffineMv(pu, pu.mvAffi[0][0], pu.mvAffi[0][1], pu.mvAffi[0][2], REF_PIC_LIST_0);
+            }
+            if (pu.refIdx[1] >= 0)
+            {
+              PU::setAllAffineMv(pu, pu.mvAffi[1][0], pu.mvAffi[1][1], pu.mvAffi[1][2], REF_PIC_LIST_1);
+            }
+            m_pcInterSearch->motionCompensation(pu, geoTmBuffer[mrgTmCand1], REF_PIC_LIST_X, false, true);
+            pu.cu->affine = false;
+            isGeoTmChromaAvail[mrgTmCand1] = 1;
+          }
+        }
+        else
+        {
+#endif
         int geoTmType = g_geoTmShape[1][g_geoParams[splitDir][0]];
         mrgTmCand1 = mergeCand1 + (geoTmType - 1) * GEO_MAX_NUM_UNI_CANDS;
         if (isChromaEnabled(pu.chromaFormat) && !isGeoTmChromaAvail[mrgTmCand1])
@@ -13602,6 +13934,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
           isGeoTmChromaAvail[mrgTmCand1] = true;
         }
+#if JVET_AJ0274_GPM_AFFINE_TM
+        }
+#endif
       }
 #endif
 #if JVET_AG0164_AFFINE_GPM
@@ -13722,6 +14057,10 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
           int geoTmType = g_geoTmShape[0][g_geoParams[splitDir][0]];
           mergeCtx[geoTmType].setMergeInfo(pu, mergeCand0);
         }
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+        chromaAvailPtr0 = &isGeoTmChromaAvail[mrgTmCand0];
+        predSrcTemp0 = geoTmTempBuf[mrgTmCand0];
 #endif
       }
 #endif
@@ -13806,7 +14145,19 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         predSrc1 = geoTmBuffer[mrgTmCand1];
 #if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
         int geoTmType = g_geoTmShape[1][g_geoParams[splitDir][0]];
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (isAffine1)
+        {
+          affTmMergeCtx.setAffMergeInfo(pu, mergeCand1);
+          pu.cu->affine = false;
+        }
+        else
+#endif
         mergeCtx[geoTmType].setMergeInfo(pu, mergeCand1);
+#endif
+#if JVET_AJ0274_GPM_AFFINE_TM
+        chromaAvailPtr1 = &isGeoTmChromaAvail[mrgTmCand1];
+        predSrcTemp1 = geoTmTempBuf[mrgTmCand1];
 #endif
       }
 #endif
@@ -14073,9 +14424,36 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         }
 
         int geoCombIdx = candidateIdx * GEO_BLENDING_NUM + bldIdx;
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (tmFlag0 || tmFlag1)
+        {
+          predSrcTemp0 = geoTmTempBuf[mrgTmCand0];
+          predSrcTemp1 = geoTmTempBuf[mrgTmCand1];
+        }
+        else
+        {
+#endif
         predSrcTemp0 = mmvdFlag0? geoMMVDTempBuf[mergeCand0][mmvdCand0]: geoTempBuf[mergeCand0];
         predSrcTemp1 = mmvdFlag1? geoMMVDTempBuf[mergeCand1][mmvdCand1]: geoTempBuf[mergeCand1];
+#if JVET_AJ0274_GPM_AFFINE_TM
+        }
+#endif
+
 
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (tmFlag0)
+        {
+#if JVET_AA0058_GPM_ADAPTIVE_BLENDING
+          m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, bldIdx, CHANNEL_TYPE_LUMA, geoCombinations[geoCombIdx], predSrcTemp0, predSrcTemp1);
+          m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, bldIdx, CHANNEL_TYPE_CHROMA, geoCombinations[geoCombIdx], predSrcTemp0, predSrcTemp1);
+#else
+          m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, CHANNEL_TYPE_LUMA, geoCombinations[candidateIdx], predSrc0, predSrc1);
+          m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, CHANNEL_TYPE_CHROMA, geoCombinations[candidateIdx], predSrc0, predSrc1);
+#endif
+        }
+        else
+        {
+#endif
         PelUnitBuf  obmcBuf0 = m_ciipBuffer[0].getBuf(localUnitArea);   // Borrow the CIIP buffer
         PelUnitBuf  obmcBuf1 = m_ciipBuffer[1].getBuf(localUnitArea);   // Borrow the CIIP buffer
 
@@ -14089,6 +14467,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, CHANNEL_TYPE_LUMA, geoCombinations[candidateIdx], predSrc0, predSrc1);
         m_pcInterSearch->weightedGeoBlkRounded(pu, splitDir, CHANNEL_TYPE_CHROMA, geoCombinations[candidateIdx], predSrc0, predSrc1);
 #endif 
+#if JVET_AJ0274_GPM_AFFINE_TM
+        }
+#endif
       }
 #endif
       else
@@ -14308,6 +14689,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         pu.geoSplitDir = geoSplitDirList[candidateIdx];
         pu.geoMergeIdx0 = geoMergeCand0[candidateIdx];
         pu.geoMergeIdx1 = geoMergeCand1[candidateIdx];
+#if JVET_AJ0274_REGRESSION_GPM_TM
+        pu.geoBlendTmFlag = false;
+#endif
 #if JVET_AE0046_BI_GPM
         PU::setGpmDirMode(pu);
 #endif
@@ -14366,12 +14750,20 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 
 #if JVET_AG0164_AFFINE_GPM
         pu.affineGPM[0] = pu.affineGPM[1] = 0;
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (pu.geoMergeIdx0 < GEO_MAX_ALL_INTER_UNI_CANDS && pu.geoMergeIdx0 >= numRegularGpmMergeCand)
+#else
         if (!pu.geoTmFlag0 && pu.geoMergeIdx0 < GEO_MAX_ALL_INTER_UNI_CANDS && pu.geoMergeIdx0 >= numRegularGpmMergeCand)
+#endif
         {
           pu.geoMergeIdx0 -= numRegularGpmMergeCand;
           pu.affineGPM[0] = 1;
         }
+#if JVET_AJ0274_GPM_AFFINE_TM
+        if (pu.geoMergeIdx1 < GEO_MAX_ALL_INTER_UNI_CANDS && pu.geoMergeIdx1 >= numRegularGpmMergeCand)
+#else
         if (!pu.geoTmFlag1 && pu.geoMergeIdx1 < GEO_MAX_ALL_INTER_UNI_CANDS && pu.geoMergeIdx1 >= numRegularGpmMergeCand)
+#endif
         {
           pu.geoMergeIdx1 -= numRegularGpmMergeCand;
           pu.affineGPM[1] = 1;
@@ -14384,7 +14776,21 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
           if(pu.tmMergeFlag)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            int cand0 = pu.geoMergeIdx0;
+            int cand1 = pu.geoMergeIdx1;
+            if (pu.affineGPM[0])
+            {
+              cand0 += numRegularGpmMergeCand;
+            }
+            if (pu.affineGPM[1])
+            {
+              cand1 += numRegularGpmMergeCand;
+            }
+            int geoSyntaxMode = m_pcInterSearch->convertGeoSplitModeToSyntax(pu.geoSplitDir, cand0, cand1, tmMmvdBufIdx0 - 1, tmMmvdBufIdx1 - 1);
+#else
             int geoSyntaxMode = m_pcInterSearch->convertGeoSplitModeToSyntax(pu.geoSplitDir, pu.geoMergeIdx0, pu.geoMergeIdx1, tmMmvdBufIdx0 - 1, tmMmvdBufIdx1 - 1);
+#endif
             CHECK(geoSyntaxMode < 0 || geoSyntaxMode >= GEO_NUM_SIG_PARTMODE, "Invalid GEO split direction!");
             CHECK(pu.geoMMVDFlag0 || pu.geoMMVDFlag1, "GPM MMVD should not be used in GPM-TM mode");
             pu.geoSyntaxMode = (uint8_t)geoSyntaxMode;
@@ -14491,6 +14897,14 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if TM_MRG
           if (pu.geoTmFlag0)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            if (pu.affineGPM[0])
+            {
+              affTmMergeCtx.setAffMergeInfo(pu, pu.geoMergeIdx0);
+              pu.cu->affine = false;
+            }
+            else
+#endif
             mrgTmCtx0->setMergeInfo(pu, pu.geoMergeIdx0);
           }
           else
@@ -14518,6 +14932,14 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if TM_MRG
           if (pu.geoTmFlag1)
           {
+#if JVET_AJ0274_GPM_AFFINE_TM
+            if (pu.affineGPM[1])
+            {
+              affTmMergeCtx.setAffMergeInfo(pu, pu.geoMergeIdx1);
+              pu.cu->affine = false;
+            }
+            else
+#endif
             mrgTmCtx1->setMergeInfo(pu, pu.geoMergeIdx1);
           }
           else
@@ -14553,6 +14975,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF]
 #if JVET_AG0164_AFFINE_GPM
           , affMergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+          , affTmMergeCtx
+#endif
 #endif
           , *mrgTmCtx0, *mrgTmCtx1, pu.geoSplitDir, pu.geoMergeIdx0, pu.geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, pu.geoBldIdx, m_pcIntraSearch->m_intraMPM,
 #if JVET_AI0082_GPM_WITH_INTER_IBC
@@ -14719,6 +15144,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       pu.mmvdMergeFlag = false;
       pu.mmvdMergeIdx = MAX_UCHAR;
 
+#if JVET_AJ0274_REGRESSION_GPM_TM
+      pu.geoBlendTmFlag = false;
+#endif
       if (noResidualPass == iterationBegin)
       {
         // do chroma (luma has been done yet)
@@ -14726,7 +15154,11 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         {
           const int mergeCand = geoBI.mergeCand[k];
           mergeCtx[GEO_TM_OFF].setMergeInfo(pu, mergeCand);
+#if JVET_AJ0274_REGRESSION_GPM_TM
+          if (isGeoChromaAvail[mergeCand])
+#else
           if (isGeoChromaAvail[mergeCand] == 2)
+#endif
           {
             continue;
           }
@@ -14779,12 +15211,22 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       uint8_t intraMPM[2] = { PLANAR_IDX, PLANAR_IDX };
 #if JVET_AG0164_AFFINE_GPM
 #if JVET_AI0082_GPM_WITH_INTER_IBC
+#if JVET_AJ0274_GPM_AFFINE_TM
+      PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF], affMergeCtx, affTmMergeCtx, mergeCtx[GEO_TM_OFF], mergeCtx[GEO_TM_OFF], 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, geoBvList,
+        pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx1] : nullptr);
+#else
       PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF], affMergeCtx, mergeCtx[GEO_TM_OFF], mergeCtx[GEO_TM_OFF], 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, geoBvList,
         pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx1] : nullptr);
+#endif
+#else
+#if JVET_AJ0274_GPM_AFFINE_TM
+      PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF], affMergeCtx, affTmMergeCtx, mergeCtx[GEO_TM_OFF], mergeCtx[GEO_TM_OFF], 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM,
+        pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx1] : nullptr);
 #else
       PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF], affMergeCtx, mergeCtx[GEO_TM_OFF], mergeCtx[GEO_TM_OFF], 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM,
         pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx1] : nullptr);
 #endif
+#endif
 #else
 #if JVET_AI0082_GPM_WITH_INTER_IBC
       PU::spanGeoMMVDMotionInfo(pu, mergeCtx[GEO_TM_OFF], mergeCtx[GEO_TM_OFF], mergeCtx[GEO_TM_OFF], 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, geoBvList,
@@ -14794,7 +15236,6 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
         pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4GPM[GEO_TM_OFF][geoMergeIdx1] : nullptr);
 #endif
 #endif
-
       tempCS->getPredBuf().copyFrom(blendBuffer);
 
 #if ENABLE_OBMC
@@ -14827,6 +15268,7 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
       tempCS->initStructData(encTestMode.qp);
 
       bIsBestCost |= lastBestCost > bestCS->cost;
+
       if (!bIsBestCost && (i + 1) >= 2)
       {
         bStopRdoLoop = true;
@@ -14835,6 +15277,465 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
   } // i (numGeoBlendInfoCand)
 #endif
 
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  double  bestEstimGeoBlendTmPredCost = MAX_DOUBLE;
+  uint8_t isGeoBlendTmChromaAvail[GEO_TM_MAX_NUM_CANDS];
+  memset(isGeoBlendTmChromaAvail, 0, sizeof(uint8_t) * GEO_TM_MAX_NUM_CANDS);
+  {
+    int idxBufGeoTm = idxBlendGeoFirst;
+#if JVET_AG0164_AFFINE_GPM
+    uint8_t maxNumBlendTmMrgCand = numRegularGpmMergeCand;
+#else
+    uint8_t maxNumBlendTmMrgCand = maxNumMergeCandidates;
+#endif
+    PelUnitBuf geoBlendTmBuffer[GEO_TM_MAX_NUM_CANDS];
+    geoBlendTmCtx.numValidMergeCand = maxNumBlendTmMrgCand;
+    GeoBlendInfo geoBlendTmInfo[GEO_BLEND_MAX_NUM_CANDS];
+    int numGeoBlendTmInfoCand = 0;
+    GeoBlendInfo  geoTmBIdst;
+
+    bool skipGeoBlendTM = CU::checkGeoBlendTmAvail(cu, bestCS);
+
+    if (!skipGeoBlendTM)
+    {
+      tempCS->initStructData(encTestMode.qp);
+      CodingUnit& cu = tempCS->addCU(tempCS->area, pm.chType);
+      pm.setCUData(cu);
+      cu.predMode = MODE_INTER;
+      cu.slice = tempCS->slice;
+      cu.tileIdx = tempCS->pps->getTileIdx(tempCS->area.lumaPos());
+      cu.qp = encTestMode.qp;
+      cu.affine = false;
+      cu.mtsFlag = false;
+#if INTER_LIC
+      cu.licFlag = false;
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+      cu.licInheritPara = false;
+#endif
+#endif
+      cu.bcwIdx = BCW_DEFAULT;
+      cu.geoFlag = true;
+#if JVET_AG0112_REGRESSION_BASED_GPM_BLENDING
+      cu.geoBlendFlag = true;
+#endif
+#if JVET_AG0061_INTER_LFNST_NSPT
+      cu.lfnstFlag = false;
+      cu.lfnstIdx = 0;
+#if JVET_AI0050_INTER_MTSS
+      cu.lfnstIntra = 0;
+#endif
+#endif
+      cu.imv = 0;
+      cu.mmvdSkip = false;
+      cu.skip = false;
+      cu.mipFlag = false;
+      cu.bdpcmMode = 0;
+
+      PredictionUnit& pu = tempCS->addPU(cu, pm.chType);
+      pu.mergeFlag = true;
+      pu.regularMergeFlag = false;
+#if JVET_AJ0274_REGRESSION_GPM_TM
+      pu.geoBlendTmFlag = false;
+#endif
+#if JVET_AE0046_BI_GPM
+      PU::setGpmDirMode(pu);
+#endif
+#if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
+      pu.tmMergeFlag = false;
+#endif
+#if JVET_AG0164_AFFINE_GPM
+      pu.affineGPM[0] = pu.affineGPM[1] = 0;
+#endif
+
+      for (int idx = 0; idx < maxNumBlendTmMrgCand; idx++)
+      {
+        if (mrgDuplicated[idx])
+        {
+          continue;
+        }
+        geoBlendTmCtx.bcwIdx[idx] = BCW_DEFAULT;
+        geoBlendTmCtx.useAltHpelIf[idx] = false;
+#if JVET_AG0276_NLIC
+        geoBlendTmCtx.altLMFlag[idx] = false;
+        geoBlendTmCtx.altLMParaNeighbours[idx].resetAltLinearModel();
+#endif
+#if INTER_LIC
+        geoBlendTmCtx.licFlags[idx] = mergeCtx[GEO_TM_OFF].licFlags[idx];
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+        geoBlendTmCtx.copyLICParamFromCtx(idx, mergeCtx[GEO_TM_OFF], idx);
+#else
+        geoBlendTmCtx.setDefaultLICParamToCtx(idx);
+#endif
+#endif
+        geoBlendTmCtx.interDirNeighbours[idx] = mergeCtx[GEO_TM_OFF].interDirNeighbours[idx];
+        geoBlendTmCtx.mvFieldNeighbours[(idx << 1)].mv = mergeCtx[GEO_TM_OFF].mvFieldNeighbours[(idx << 1)].mv;
+        geoBlendTmCtx.mvFieldNeighbours[(idx << 1) + 1].mv = mergeCtx[GEO_TM_OFF].mvFieldNeighbours[(idx << 1) + 1].mv;
+        geoBlendTmCtx.mvFieldNeighbours[(idx << 1)].refIdx = mergeCtx[GEO_TM_OFF].mvFieldNeighbours[(idx << 1)].refIdx;
+        geoBlendTmCtx.mvFieldNeighbours[(idx << 1) + 1].refIdx = mergeCtx[GEO_TM_OFF].mvFieldNeighbours[(idx << 1) + 1].refIdx;
+      }
+
+      pu.geoTmType = GEO_TM_SHAPE_AL;
+      pu.geoBlendTmFlag = true;
+      pu.cu->geoBlendFlag = true;
+      pu.tmMergeFlag = true;
+      bool tempBdvrFlag = pu.bdmvrRefine;
+
+      for (uint8_t mrgIdx = 0; mrgIdx < maxNumBlendTmMrgCand; mrgIdx++)
+      {
+        if (mrgDuplicated[mrgIdx])
+        {
+          continue;
+        }
+        uint8_t mergeCand = mrgIdx + (GEO_TM_SHAPE_AL - 1) * GEO_MAX_NUM_UNI_CANDS;
+        if (isGeoTmMCAvail[mergeCand])
+        {
+          mergeCtx[GEO_TM_SHAPE_AL].setMergeInfo(pu, mrgIdx);
+        }
+        else
+        {
+          geoBlendTmCtx.setMergeInfo(pu, mrgIdx);
+#if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE
+          m_pcInterSearch->deriveTMMv(pu, NULL, mrgIdx);
+#else
+          m_pcInterSearch->deriveTMMv(pu);
+#endif
+        }
+        geoBlendTmCtx.interDirNeighbours[mrgIdx] = pu.interDir;
+        geoBlendTmCtx.bcwIdx[mrgIdx] = (pu.interDir != 3) ? BCW_DEFAULT : geoBlendTmCtx.bcwIdx[mrgIdx];
+        geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1)].refIdx = pu.refIdx[0];
+        geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1) + 1].refIdx = pu.refIdx[1];
+        geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1)].mv = pu.mv[0];
+        geoBlendTmCtx.mvFieldNeighbours[(mrgIdx << 1) + 1].mv = pu.mv[1];
+      }
+      pu.bdmvrRefine = tempBdvrFlag;
+      pu.tmMergeFlag = false;
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+      cu.licFlag = false;
+      geoBlendTmCtx.setLICParamToPu(*cu.firstPU, NOT_VALID, false);
+#endif
+      m_pcInterSearch->getGeoBlendCand(cu, geoBlendTmCtx, -1, geoTmBIdst, geoBlendTmInfo, &numGeoBlendTmInfoCand);
+      for (int i = 0; i < numGeoBlendTmInfoCand; i++)
+      {
+        for (int j = 0; j < 2; j++)
+        {
+          auto mergeCand = geoBlendTmInfo[i].mergeCand[j];
+
+          if (mrgDuplicated[mergeCand])
+          {
+            continue;
+          }
+          if (isGeoTmMCAvail[mergeCand] == 2)
+          {
+            continue;
+          }
+          geoBlendTmCtx.setMergeInfo(pu, mergeCand);
+          geoBlendTmBuffer[mergeCand] = m_acGeoBlendTMBuffer[mergeCand].getBuf(localUnitArea);
+
+#if JVET_AE0046_BI_GPM
+          if (PU::checkBDMVRCondition(pu, true))
+          {
+            pu.bdmvrRefine = true;
+            refinePossibleTM[mergeCand] = true;
+            pu.gpmDmvrRefinePart0 = pu.bdmvrRefine;
+            PU::spanPuMv2DmvrBuffer(pu, m_mvBufBDMVR4GPM[0], m_mvBufBDMVR4GPM[1]);
+          }
+#endif
+          if (isGeoTmMCAvail[mergeCand] == 1)
+          {
+            geoBlendTmBuffer[mergeCand].copyFrom(geoTmBuffer[mergeCand]);
+            isGeoBlendTmChromaAvail[mergeCand] = 1;
+          }
+          else
+          {
+            m_pcInterSearch->motionCompensation(pu, geoBlendTmBuffer[mergeCand], REF_PIC_LIST_X, true, false);
+          }
+
+#if JVET_AE0046_BI_GPM
+          if (pu.bdmvrRefine)
+          {
+            pu.bdmvrRefine = false;
+            pu.gpmDmvrRefinePart0 = pu.bdmvrRefine;
+            if (isGeoTmMCAvail[mergeCand] == 1)
+            {
+              ::memcpy(m_mvBufEncBDOF4TMBlend[mergeCand], m_mvBufEncBDOF4GPM[GEO_TM_SHAPE_AL][mergeCand], sizeof(Mv) * BDOF_SUBPU_MAX_NUM);
+            }
+            else
+            {
+              ::memcpy(m_mvBufEncBDOF4TMBlend[mergeCand], m_pcInterSearch->getBdofSubPuMvOffset(), sizeof(Mv) * BDOF_SUBPU_MAX_NUM);
+            }
+          }
+#endif
+          isGeoTmMCAvail[mergeCand] = 2;
+        }
+      }
+      idxBufGeoTm = idxBlendGeoFirst;
+      for (int i = 0; i < numGeoBlendTmInfoCand; i++)
+      {
+        GeoBlendInfo& geoBI = geoBlendTmInfo[i];
+
+        pu.cu->blendModel.copy(geoBI.blendModel);
+
+        int  mergeCand0 = geoBI.mergeCand[0];
+        int  mergeCand1 = geoBI.mergeCand[1];
+
+        PelUnitBuf  blendBuffer = m_acMergeBuffer[idxBufGeoTm].getBuf(localUnitArea);
+        m_pcInterSearch->weightedBlend(pu, blendBuffer, geoBlendTmBuffer[mergeCand0], geoBlendTmBuffer[mergeCand1], false, true, true);
+
+        DistParam& distParamGeo = distParamWholeBlkGeoBlend;   // SAD
+
+        distParamGeo.cur.buf = blendBuffer.Y().buf;
+        distParamGeo.cur.stride = blendBuffer.Y().stride;
+        Distortion sad = distParamGeo.distFunc(distParamGeo);
+
+        geoBI.sad = sad;        // sad bi-prediction geo-blended distortion
+        geoBI.idxBufGeo = idxBufGeoTm;
+      }
+
+      for (int idx = 0; idx < numGeoBlendTmInfoCand; idx++)
+      {
+#if JVET_AG0164_AFFINE_GPM
+        geoBlendCandCost[idx] = geoMergeIdxCost[std::min(idx, numRegularGpmMergeCand - 1)];
+#else
+        geoBlendCandCost[idx] = geoMergeIdxCost[std::min(idx, maxNumMergeCandidates - 1)];
+#endif
+        GeoBlendInfo& geoBI = geoBlendTmInfo[idx];
+
+        geoBI.uiCost = (double)geoBI.sad + geoBlendCandCost[idx] + geoBlendFlagCost[1] + geoTMFlagCost[1];
+
+        bestEstimGeoBlendTmPredCost = std::min(geoBI.uiCost, bestEstimGeoBlendTmPredCost);
+
+        geoBI.iMergeIdx = idx;
+      }
+
+      pu.geoBldIdx = 0;
+
+      // encoder re-order with uiCost
+      for (int i = 0; i < (numGeoBlendTmInfoCand - 1); i++)
+      {
+        for (int j = (i + 1); j < numGeoBlendTmInfoCand; j++)
+        {
+          if (geoBlendTmInfo[j].uiCost < geoBlendTmInfo[i].uiCost)
+          {
+            std::swap(geoBlendTmInfo[i], geoBlendTmInfo[j]);
+          }
+        }
+      }
+
+      bStopRdoLoop = false;
+      bIsBestCost = false;  // current CU-geoBlend is best
+      tempCS->initStructData(encTestMode.qp);
+
+      for (uint8_t i = 0; i < numGeoBlendTmInfoCand && !bStopRdoLoop; i++)
+      {
+        double geoBlendFastRatio = MRG_FAST_RATIO;
+        double geoBlendFastRatioBest = 1.0;
+        geoBlendFastRatioBest = 1.25;
+        if (geoBlendTmInfo[i].uiCost > geoBlendFastRatio * bestEstimGeoBlendTmPredCost || geoBlendTmInfo[i].uiCost > geoBlendFastRatioBest * getMergeBestSATDCost())
+        {
+          continue;
+        }
+
+        bool  geoBlendCandHasNoResidual = false;
+        for (uint8_t noResidualPass = iterationBegin; noResidualPass < iteration; ++noResidualPass)
+        {
+          if (((noResidualPass != 0) && geoBlendCandHasNoResidual)
+            //  || ((noResidualPass == 0) && bestIsSkip)
+            )
+          {
+            continue;
+          }
+
+          GeoBlendInfo& geoBI = geoBlendTmInfo[i];
+
+          PelUnitBuf blendBuffer = m_acMergeBuffer[geoBI.idxBufGeo].getBuf(localUnitArea);
+
+          CodingUnit& cu = tempCS->addCU(tempCS->area, pm.chType);
+          pm.setCUData(cu);
+          cu.predMode = MODE_INTER;
+          cu.slice = tempCS->slice;
+          cu.tileIdx = tempCS->pps->getTileIdx(tempCS->area.lumaPos());
+          cu.qp = encTestMode.qp;
+          cu.affine = false;
+          cu.mtsFlag = false;
+#if INTER_LIC
+          cu.licFlag = false;
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+          cu.licInheritPara = false;
+#endif
+#endif
+          cu.bcwIdx = BCW_DEFAULT;
+          cu.geoBlendFlag = true;
+          cu.blendModel.copy(geoBI.blendModel);
+          cu.geoFlag = true;
+          cu.imv = 0;
+          cu.mmvdSkip = false;
+          cu.skip = false;
+          cu.mipFlag = false;
+          cu.bdpcmMode = 0;
+          PredictionUnit& pu = tempCS->addPU(cu, pm.chType);
+          pu.mergeFlag = true;
+          pu.regularMergeFlag = false;
+          pu.geoSplitDir = 0;
+          pu.geoMergeIdx0 = geoBI.iMergeIdx;
+          pu.geoMergeIdx1 = geoBI.iMergeIdx;
+#if JVET_AG0164_AFFINE_GPM
+          pu.affineGPM[0] = 0;
+          pu.affineGPM[1] = 0;
+#endif
+          pu.geoBlendTmFlag = true;
+#if JVET_AE0046_BI_GPM
+          PU::setGpmDirMode(pu);
+#endif
+#if JVET_Y0065_GPM_INTRA
+          pu.gpmIntraFlag = false;
+#if ENABLE_DIMD
+          cu.dimdMode = dimdMode;
+#endif
+#if JVET_W0123_TIMD_FUSION
+          cu.timdMode = timdMode;
+#if JVET_AC0094_REF_SAMPLES_OPT
+          cu.timdModeCheckWA = timdModeCheckWA;
+#endif
+#endif
+#endif
+#if JVET_AA0058_GPM_ADAPTIVE_BLENDING
+          pu.geoBldIdx = -1;
+#endif
+#if JVET_Z0056_GPM_SPLIT_MODE_REORDERING
+          if (sps.getUseAltGPMSplitModeCode())
+          {
+            pu.geoSyntaxMode = 0;
+          }
+#endif
+#if TM_MRG
+          pu.tmMergeFlag = false;
+          pu.geoTmFlag0 = false;
+          pu.geoTmFlag1 = false;
+#endif
+          pu.geoMMVDFlag0 = false;
+          pu.geoMMVDFlag1 = false;
+
+          pu.mmvdMergeFlag = false;
+          pu.mmvdMergeIdx = MAX_UCHAR;
+
+          if (noResidualPass == iterationBegin)
+          {
+            // do chroma (luma has been done yet)
+            for (int k = 0; k < 2; k++)
+            {
+              const int mergeCand = geoBI.mergeCand[k];
+              if ((isGeoBlendTmChromaAvail[mergeCand] == 1 && isGeoTmChromaAvail[mergeCand]) || isGeoBlendTmChromaAvail[mergeCand] == 2)
+              {
+                continue;
+              }
+              geoBlendTmCtx.setMergeInfo(pu, mergeCand);
+
+#if JVET_AE0046_BI_GPM
+              if (refinePossibleTM[mergeCand])
+              {
+                pu.bdmvrRefine = true;
+                PU::spanPuMv2DmvrBuffer(pu, m_mvBufBDMVR4GPM[0], m_mvBufBDMVR4GPM[1]);
+                ::memcpy(m_pcInterSearch->getBdofSubPuMvOffset(), m_mvBufEncBDOF4TMBlend[mergeCand], sizeof(Mv) * BDOF_SUBPU_MAX_NUM);
+                m_pcInterSearch->setLumaBdofReady(true);
+              }
+#endif
+              m_pcInterSearch->motionCompensation(pu, geoBlendTmBuffer[mergeCand], REF_PIC_LIST_X, false, true);
+
+#if JVET_AE0046_BI_GPM
+              pu.bdmvrRefine = false;
+              m_pcInterSearch->setLumaBdofReady(false);
+#endif
+              isGeoBlendTmChromaAvail[mergeCand] = 2;
+            }
+          }
+
+#if JVET_AH0314_LIC_INHERITANCE_FOR_MRG
+          geoBlendTmCtx.setMergeInfo(pu, geoBI.mergeCand[1]);
+#else
+          geoBlendTmCtx.setMergeInfo(pu, 0);
+#endif
+
+          pu.interDir = 3;
+          pu.mergeIdx = MAX_UCHAR;
+          pu.geoMergeIdx0 = geoBI.mergeCand[0];
+          pu.geoMergeIdx1 = geoBI.mergeCand[1];
+
+          pu.cu->blendModel.copy(geoBI.blendModel);
+
+          if (noResidualPass == iterationBegin)
+          {
+            m_pcInterSearch->weightedBlend(pu, blendBuffer, geoBlendTmBuffer[geoBI.mergeCand[0]], geoBlendTmBuffer[geoBI.mergeCand[1]], false, false, true); // do again luma since OBMC has been applied
+          }
+
+          int geoMergeIdx0 = geoBI.mergeCand[0];
+          int geoMergeIdx1 = geoBI.mergeCand[1];
+
+          pu.gpmDmvrRefinePart0 = refinePossibleTM[geoMergeIdx0];
+          pu.gpmDmvrRefinePart1 = refinePossibleTM[geoMergeIdx1];
+
+          CHECK(pu.geoTmFlag0 || pu.geoMMVDFlag0 || pu.geoTmFlag1 || pu.geoMMVDFlag1, "spanGeoMMVDMotionInfo() failed");
+
+          uint8_t intraMPM[2] = { PLANAR_IDX, PLANAR_IDX };
+#if JVET_AG0164_AFFINE_GPM
+#if JVET_AI0082_GPM_WITH_INTER_IBC
+#if JVET_AJ0274_GPM_AFFINE_TM
+          PU::spanGeoMMVDMotionInfo(pu, geoBlendTmCtx, affMergeCtx, affTmMergeCtx, geoBlendTmCtx, geoBlendTmCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, geoBvList,
+            pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4TMBlend[geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4TMBlend[geoMergeIdx1] : nullptr);
+#else
+          PU::spanGeoMMVDMotionInfo(pu, geoBlendTmCtx, affMergeCtx, geoBlendTmCtx, geoBlendTmCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM, geoBvList,
+            pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4TMBlend[geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4TMBlend[geoMergeIdx1] : nullptr);
+#endif
+#else
+          PU::spanGeoMMVDMotionInfo(pu, geoBlendTmCtx, affMergeCtx, geoBlendTmCtx, geoBlendTmCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM,
+            pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4TMBlend[geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4TMBlend[geoMergeIdx1] : nullptr);
+#endif
+#else
+          PU::spanGeoMMVDMotionInfo(pu, geoBlendTmCtx, geoBlendTmCtx, geoBlendTmCtx, 0, geoMergeIdx0, geoMergeIdx1, pu.geoTmFlag0, pu.geoMMVDFlag0, pu.geoMMVDIdx0, pu.geoTmFlag1, pu.geoMMVDFlag1, pu.geoMMVDIdx1, 0, intraMPM,
+            pu.gpmDmvrRefinePart0, pu.gpmDmvrRefinePart1, pu.gpmDmvrRefinePart0 ? m_mvBufEncBDOF4GPM[GEO_TM_SHAPE_AL][geoMergeIdx0] : nullptr, pu.gpmDmvrRefinePart1 ? m_mvBufEncBDOF4GPM[GEO_TM_SHAPE_AL][geoMergeIdx1] : nullptr);
+#endif
+
+          tempCS->getPredBuf().copyFrom(blendBuffer);
+
+#if ENABLE_OBMC
+          if (!pu.gpmIntraFlag)
+          {
+            cu.isobmcMC = true;
+            cu.obmcFlag = true;
+#if JVET_AJ0161_OBMC_EXT_WITH_INTRA_PRED
+            m_pcInterSearch->subBlockOBMC(pu, nullptr, m_pcIntraSearch);
+#else
+            m_pcInterSearch->subBlockOBMC(pu);
+#endif
+            cu.isobmcMC = false;
+          }
+#endif
+
+          pu.mergeIdx = MAX_UCHAR;
+          pu.geoMergeIdx0 = geoBI.iMergeIdx;
+          pu.geoMergeIdx1 = MAX_UCHAR;
+          CHECK(i >= pu.cs->sps->getMaxNumGeoCand(), "geoBlend idx should be < sps->getMaxNumGeoCand()");
+
+          double lastBestCost = bestCS->cost;
+
+          xEncodeInterResidual(tempCS, bestCS, pm, encTestMode, noResidualPass, (noResidualPass == 0 ? &geoBlendCandHasNoResidual : NULL));
+
+          if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip)
+          {
+            bestIsSkip = bestCS->getCU(pm.chType)->rootCbf == 0;
+          }
+          tempCS->initStructData(encTestMode.qp);
+
+          bIsBestCost |= lastBestCost > bestCS->cost;
+          if (!bIsBestCost && (i + 1) >= 2)
+          {
+            bStopRdoLoop = true;
+          }
+        } // noResidualPass
+      } // i (numGeoBlendInfoCand)
+    }
+  }
+#endif
+
   if (m_bestModeUpdated && bestCS->cost != MAX_DOUBLE)
   {
     xCalDebCost(*bestCS, pm);
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 8f16a4d7074e8f83b4dff429e665bc4c6c121613..ae0e5cff63e62f7adcde06d4cf039a105afea21c 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -371,6 +371,9 @@ private:
 #endif
   FastGeoMMVDCostList   m_geoMMVDCostList;
   bool                  m_fastGpmMmvdSearch;
+#if JVET_AJ0274_GPM_AFFINE_TM
+  int                  m_fastGpmAffSearch;
+#endif
   bool                  m_fastGpmMmvdRelatedCU;
   bool                  m_includeMoreMMVDCandFirstPass;
   int                   m_maxNumGPMDirFirstPass;
@@ -379,6 +382,9 @@ private:
   PelStorage            m_acGeoMergeTmpBuffer[GEO_TM_MAX_NUM_CANDS];
   PelStorage            m_acGeoSADTmpBuffer[GEO_TM_MAX_NUM_CANDS];
 #endif
+#endif
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  PelStorage            m_acGeoBlendTMBuffer[GEO_TM_MAX_NUM_CANDS];
 #endif
   double                m_AFFBestSATDCost;
   double                m_mergeBestSATDCost;
@@ -405,6 +411,9 @@ private:
 #endif
   Mv                    m_mvBufEncBDOF[MRG_MAX_NUM_CANDS][BDOF_SUBPU_MAX_NUM];
   Mv                    m_mvBufEncBDOF4TM[MRG_MAX_NUM_CANDS][BDOF_SUBPU_MAX_NUM];
+#if JVET_AJ0274_REGRESSION_GPM_TM
+  Mv                    m_mvBufEncBDOF4TMBlend[MRG_MAX_NUM_CANDS][BDOF_SUBPU_MAX_NUM];
+#endif
 #if JVET_X0049_ADAPT_DMVR
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   Mv                    m_mvBufBDMVR4BM[(BM_MRG_MAX_NUM_INIT_CANDS << 1)<<1][MAX_NUM_SUBCU_DMVR];
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index c0e5728573c5e154c23a9c52d4eb082707f1b75d..0450da4efcf484a8300309d836a727c4c99b3d9b 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1879,8 +1879,13 @@ void EncLib::xInitSPS( SPS& sps )
   sps.setMaxNumIBCMergeCand(getMaxNumIBCMergeCand());
   sps.setMaxNumGeoCand(getMaxNumGeoCand());
 #if JVET_AG0164_AFFINE_GPM
+#if JVET_AJ0274_GPM_AFFINE_TM
+  sps.setMaxNumGpmAffCand      (getMaxNumGpmAffCand());
+  sps.setMaxNumGpmAffTmCand    (m_intraPeriod == -1 ? (m_sourceWidth * m_sourceHeight >= 1920 * 1080 ? 0 : getMaxNumGpmAffTmCand() - 2) : getMaxNumGpmAffTmCand());
+#else
   sps.setMaxNumGpmAffCand      (((m_sourceWidth * m_sourceHeight) > (m_intraPeriod == -1 ? 1280 * 720 : 0)) ? getMaxNumGpmAffCand() : 0);
 #endif
+#endif
 #if JVET_Z0127_SPS_MHP_MAX_MRG_CAND
   sps.setMaxNumMHPCand(getMaxNumMHPCand());
 #endif
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 2a99a0f3db75e27deea79a272361019b8298469e..2c6d16ed975d5ecf6a75fbe9798a774f1501ca7c 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -8351,7 +8351,11 @@ void InterSearch::setGeoSplitModeToSyntaxTable(PredictionUnit& pu, MergeCtx& mer
 }
 
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
+#if JVET_AJ0274_GPM_AFFINE_TM
+void InterSearch::setGeoTMSplitModeToSyntaxTable(PredictionUnit& pu, MergeCtx(&mergeCtx)[GEO_NUM_TM_MV_CAND], const AffineMergeCtx& affMergeCtx, int mergeCand0, int mergeCand1, int mmvdCand0, int mmvdCand1)
+#else
 void InterSearch::setGeoTMSplitModeToSyntaxTable(PredictionUnit& pu, MergeCtx(&mergeCtx)[GEO_NUM_TM_MV_CAND], int mergeCand0, int mergeCand1, int mmvdCand0, int mmvdCand1)
+#endif
 {
   const int idx0 = mmvdCand0 + 1;
   const int idx1 = mmvdCand1 + 1;
@@ -8364,6 +8368,9 @@ void InterSearch::setGeoTMSplitModeToSyntaxTable(PredictionUnit& pu, MergeCtx(&m
                         , m_gpmPartTplCost[idx0][mergeCand0]
                         , m_gpmPartTplCost[idx1][mergeCand1]
                         , mergeCtx
+#if JVET_AJ0274_GPM_AFFINE_TM
+                        , affMergeCtx
+#endif
                         , mergeCand0
                         , mergeCand1
                         , numValidInList
@@ -8472,10 +8479,17 @@ bool InterSearch::selectGeoSplitModes(PredictionUnit &pu,
 }
 
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
-bool InterSearch::selectGeoTMSplitModes (PredictionUnit &pu, 
+#if JVET_AJ0274_GPM_AFFINE_TM
+bool InterSearch::selectGeoTMSplitModes (PredictionUnit &pu,
+                                         uint32_t (&gpmTplCostPart0)[2][GEO_NUM_PARTITION_MODE],
+                                         uint32_t (&gpmTplCostPart1)[2][GEO_NUM_PARTITION_MODE],
+                                         MergeCtx (&mergeCtx)[GEO_NUM_TM_MV_CAND], const AffineMergeCtx& affMergeCtx,int mergeCand0, int mergeCand1, uint8_t& numValidInList, uint8_t (&modeList)[GEO_NUM_SIG_PARTMODE])
+#else
+bool InterSearch::selectGeoTMSplitModes (PredictionUnit &pu,
                                          uint32_t (&gpmTplCostPart0)[2][GEO_NUM_PARTITION_MODE],
                                          uint32_t (&gpmTplCostPart1)[2][GEO_NUM_PARTITION_MODE],
                                          MergeCtx (&mergeCtx)[GEO_NUM_TM_MV_CAND], int mergeCand0, int mergeCand1, uint8_t& numValidInList, uint8_t (&modeList)[GEO_NUM_SIG_PARTMODE])
+#endif
 {
   if (!m_bAMLTemplateAvailabe[0] && !m_bAMLTemplateAvailabe[1])
   {
@@ -8483,7 +8497,11 @@ bool InterSearch::selectGeoTMSplitModes (PredictionUnit &pu,
     return false;
   }
 
+#if JVET_AJ0274_GPM_AFFINE_TM
+  if (PU::checkRprRefExistingInGpm(pu, mergeCtx[GEO_TM_OFF], mergeCand0, mergeCtx[GEO_TM_OFF], mergeCand1, affMergeCtx))
+#else
   if (PU::checkRprRefExistingInGpm(pu, mergeCtx[GEO_TM_OFF], mergeCand0, mergeCtx[GEO_TM_OFF], mergeCand1))
+#endif
   {
     bool backupTplValid[2] = {m_bAMLTemplateAvailabe[0], m_bAMLTemplateAvailabe[1]};
     m_bAMLTemplateAvailabe[0] = false;
@@ -8504,15 +8522,25 @@ bool InterSearch::selectGeoTMSplitModes (PredictionUnit &pu,
   // First partition
   if (fillRefTplPart0)
   {
+#if JVET_AJ0274_GPM_AFFINE_TM
+    fillPartGPMRefTemplate<0, false>(pu, mergeCtx[GEO_TM_SHAPE_AL], mergeCand0, -1, pRefTopPart0[GEO_TM_SHAPE_AL], pRefLeftPart0[GEO_TM_SHAPE_AL], &affMergeCtx);
+    fillPartGPMRefTemplate<0, false>(pu, mergeCtx[GEO_TM_SHAPE_A ], mergeCand0, -1, pRefTopPart0[GEO_TM_SHAPE_A ], pRefLeftPart0[GEO_TM_SHAPE_A ], &affMergeCtx);
+#else
     fillPartGPMRefTemplate<0, false>(pu, mergeCtx[GEO_TM_SHAPE_AL], mergeCand0, -1, pRefTopPart0[GEO_TM_SHAPE_AL], pRefLeftPart0[GEO_TM_SHAPE_AL]);
     fillPartGPMRefTemplate<0, false>(pu, mergeCtx[GEO_TM_SHAPE_A ], mergeCand0, -1, pRefTopPart0[GEO_TM_SHAPE_A ], pRefLeftPart0[GEO_TM_SHAPE_A ]);
+#endif
   }
 
   // Second
   if (fillRefTplPart1)
   {
+#if JVET_AJ0274_GPM_AFFINE_TM
+    fillPartGPMRefTemplate<1, false>(pu, mergeCtx[GEO_TM_SHAPE_AL], mergeCand1, -1, pRefTopPart1[GEO_TM_SHAPE_AL], pRefLeftPart1[GEO_TM_SHAPE_AL], &affMergeCtx);
+    fillPartGPMRefTemplate<1, false>(pu, mergeCtx[GEO_TM_SHAPE_L ], mergeCand1, -1, pRefTopPart1[GEO_TM_SHAPE_L ], pRefLeftPart1[GEO_TM_SHAPE_L ], &affMergeCtx);
+#else
     fillPartGPMRefTemplate<1, false>(pu, mergeCtx[GEO_TM_SHAPE_AL], mergeCand1, -1, pRefTopPart1[GEO_TM_SHAPE_AL], pRefLeftPart1[GEO_TM_SHAPE_AL]);
     fillPartGPMRefTemplate<1, false>(pu, mergeCtx[GEO_TM_SHAPE_L ], mergeCand1, -1, pRefTopPart1[GEO_TM_SHAPE_L ], pRefLeftPart1[GEO_TM_SHAPE_L ]);
+#endif
   }
 
   // Get mode lists
diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h
index ed5b1b10d60118da84584a0e3e55bc14630e4381..a4cd38d844534d97e2e39373d73424a856fda1cf 100644
--- a/source/Lib/EncoderLib/InterSearch.h
+++ b/source/Lib/EncoderLib/InterSearch.h
@@ -1368,7 +1368,11 @@ public:
 #endif
                                   , int mmvdCand0 = -1, int mmvdCand1 = -1); // mmvdCandX = -1: regular, 0~GPM_EXT_MMVD_MAX_REFINE_NUM-1: MMVD, >=GPM_EXT_MMVD_MAX_REFINE_NUM: TM
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
+#if JVET_AJ0274_GPM_AFFINE_TM
+  void setGeoTMSplitModeToSyntaxTable(PredictionUnit& pu, MergeCtx (&mergeCtx)[GEO_NUM_TM_MV_CAND], const AffineMergeCtx &affMergeCtx, int mergeCand0, int mergeCand1, int mmvdCand0 = -1, int mmvdCand1 = -1); // mmvdCandX = -1: regular, 0~GPM_EXT_MMVD_MAX_REFINE_NUM-1: MMVD, >=GPM_EXT_MMVD_MAX_REFINE_NUM: TM
+#else
   void setGeoTMSplitModeToSyntaxTable(PredictionUnit& pu, MergeCtx (&mergeCtx)[GEO_NUM_TM_MV_CAND], int mergeCand0, int mergeCand1, int mmvdCand0 = -1, int mmvdCand1 = -1); // mmvdCandX = -1: regular, 0~GPM_EXT_MMVD_MAX_REFINE_NUM-1: MMVD, >=GPM_EXT_MMVD_MAX_REFINE_NUM: TM
+#endif
 #endif
   int  convertGeoSplitModeToSyntax(int splitDir, int mergeCand0, int mergeCand1, int mmvdCand0 = -1, int mmvdCand1 = -1); // mmvdCandX = -1: regular, 0~GPM_EXT_MMVD_MAX_REFINE_NUM-1: MMVD, >=GPM_EXT_MMVD_MAX_REFINE_NUM: TM
 #if JVET_AE0169_BIPREDICTIVE_IBC
@@ -1508,10 +1512,17 @@ protected:
                                   uint32_t (&gpmTplCostPart0)[2][GEO_NUM_PARTITION_MODE],
                                   uint32_t (&gpmTplCostPart1)[2][GEO_NUM_PARTITION_MODE]);
 #if JVET_W0097_GPM_MMVD_TM && TM_MRG
-  bool selectGeoTMSplitModes (PredictionUnit &pu, 
+#if JVET_AJ0274_GPM_AFFINE_TM
+  bool selectGeoTMSplitModes (PredictionUnit &pu,
+                              uint32_t (&gpmTplCostPart0)[2][GEO_NUM_PARTITION_MODE],
+                              uint32_t (&gpmTplCostPart1)[2][GEO_NUM_PARTITION_MODE],
+                              MergeCtx (&mergeCtx)[GEO_NUM_TM_MV_CAND], const AffineMergeCtx& affMergeCtx, int mergeCand0, int mergeCand1, uint8_t& numValidInList, uint8_t (&modeList)[GEO_NUM_SIG_PARTMODE]);
+#else
+  bool selectGeoTMSplitModes (PredictionUnit &pu,
                               uint32_t (&gpmTplCostPart0)[2][GEO_NUM_PARTITION_MODE],
                               uint32_t (&gpmTplCostPart1)[2][GEO_NUM_PARTITION_MODE],
                               MergeCtx (&mergeCtx)[GEO_NUM_TM_MV_CAND], int mergeCand0, int mergeCand1, uint8_t& numValidInList, uint8_t (&modeList)[GEO_NUM_SIG_PARTMODE]);
+#endif
   void getBestGeoTMModeListEncoder (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],
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 350d72e713be3ddde1b1462e6d888496d9500830..bdb2d71d23654628a9d1001ee3451c316293773d 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1708,6 +1708,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
       {
         WRITE_UVLC(pcSPS->getMaxNumAffineMergeCand() - pcSPS->getMaxNumGpmAffCand(), "max_num_aff_merge_cand_minus_max_num_gpm_aff_cand");
       }
+#if JVET_AJ0274_GPM_AFFINE_TM
+      if (pcSPS->getMaxNumGpmAffCand() > 0)
+      {
+        WRITE_UVLC(pcSPS->getMaxNumGpmAffTmCand(), "max_num_gpm_aff_tm_cand");
+      }
+#endif
 #endif
 
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_W0097_GPM_MMVD_TM && TM_MRG