diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg
index 2b449a99efbcb37256ed42fe5b7420dbf146e14a..40e34457346c0b031007d8705f8d51e8fac8ef9f 100644
--- a/cfg/encoder_lowdelay_vtm.cfg
+++ b/cfg/encoder_lowdelay_vtm.cfg
@@ -116,7 +116,7 @@ ALF                          : 1
 BCW                          : 1
 BcwFast                      : 1
 CIIP                         : 1
-Triangle                     : 1
+Geo                          : 1
 IBC                          : 0      # turned off in CTC
 AllowDisFracMMVD             : 1
 AffineAmvr                   : 0
diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg
index 47f57f957765ea9bc213667a1bd188cad7134c0d..87ea48f866da85363356a38eb262dd52af49f04d 100644
--- a/cfg/encoder_randomaccess_vtm.cfg
+++ b/cfg/encoder_randomaccess_vtm.cfg
@@ -129,7 +129,7 @@ BCW                          : 1
 BcwFast                      : 1
 BIO                          : 1
 CIIP                         : 1
-Triangle                     : 1
+Geo                          : 1
 IBC                          : 0      # turned off in CTC
 AllowDisFracMMVD             : 1
 AffineAmvr                   : 1
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 3b71317ac238fe468bfca2a594682e1bae4d997f..e0df3c4d0c478131d1862dea79cbc1b4945c0549 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -1295,10 +1295,10 @@ Defines the SPS-derived Log2ParallelMergeLevel variable.
 Specifies the maximum number of merge candidates to use.
 \\
 
-\Option{MaxNumTriangleCand} &
+\Option{MaxNumGeoCand} &
 %\ShortOption{\None} &
 \Default{5} &
-Specifies the maximum number of triangle merge candidates to use.
+Specifies the maximum number of geometric partitioning mode candidates to use.
 \\
 
 \Option{MaxNumIBCMergeCand} &
@@ -2170,7 +2170,7 @@ Enables signaling the below parameters either in PPS or for each slice according
   collocated_from_l0_flag & s & s & p & s \\
   six_minus_max_num_merge_cand & s & p & p & p \\
   five_minus_max_num_subblock_merge_cand & s & p & p & p \\
-  max_num_merge_cand_minus_max_num_triangle_cand & s & p & p & s \\
+  max_num_merge_cand_minus_max_num_geo_cand & s & p & p & s \\
 \end{tabular}
 \\
 
@@ -2263,6 +2263,12 @@ QP threshold above which the encoder reduces cross-component ALF usage.
 Enables or disables symmetric MVD mode.
 \\
 
+\Option{Geo} &
+%\ShortOption{\None} &
+\Default{false} &
+Enables or disables geometric partitioning mode.
+\\
+
 \Option{PLT} &
 %\ShortOption{\None} &
 \Default{false} &
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 542b3ba7e9905682ce8597745d5a9a28a1741337..2996e44372583a8ad51fc7469c2aea9d4c007bec 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -236,7 +236,11 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setNoIbcConstraintFlag                               ( m_IBCMode ? false : true );
   m_cEncLib.setNoCiipConstraintFlag                           ( !m_ciip );
   m_cEncLib.setNoFPelMmvdConstraintFlag                          ( !(m_MMVD && m_allowDisFracMMVD) );
+#if !JVET_Q0806
   m_cEncLib.setNoTriangleConstraintFlag                          ( !m_Triangle );
+#else
+  m_cEncLib.setNoGeoConstraintFlag                               ( !m_Geo );
+#endif
   m_cEncLib.setNoLadfConstraintFlag                              ( !m_LadfEnabed );
   m_cEncLib.setNoTransformSkipConstraintFlag                     ( !m_useTransformSkip );
   m_cEncLib.setNoBDPCMConstraintFlag                             ( m_useBDPCM == 0 );
@@ -429,7 +433,11 @@ void EncApp::xInitLibCfg()
   }
 #endif
   m_cEncLib.setUseCiip                                        ( m_ciip );
+#if !JVET_Q0806
   m_cEncLib.setUseTriangle                                       ( m_Triangle );
+#else
+  m_cEncLib.setUseGeo                                            ( m_Geo );
+#endif
   m_cEncLib.setUseHashME                                         ( m_HashME );
 
   m_cEncLib.setAllowDisFracMMVD                                  ( m_allowDisFracMMVD );
@@ -523,7 +531,11 @@ void EncApp::xInitLibCfg()
 
   m_cEncLib.setMaxNumMergeCand                                   ( m_maxNumMergeCand );
   m_cEncLib.setMaxNumAffineMergeCand                             ( m_maxNumAffineMergeCand );
+#if !JVET_Q0806
   m_cEncLib.setMaxNumTriangleCand                                ( m_maxNumTriangleCand );
+#else
+  m_cEncLib.setMaxNumGeoCand                                     ( m_maxNumGeoCand );
+#endif
   m_cEncLib.setMaxNumIBCMergeCand                                ( m_maxNumIBCMergeCand );
 
   //====== Weighted Prediction ========
@@ -712,7 +724,11 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setPPSMvdL1ZeroIdc                                   ( m_PPSMvdL1ZeroIdc );
   m_cEncLib.setPPSCollocatedFromL0Idc                            ( m_PPSCollocatedFromL0Idc );
   m_cEncLib.setPPSSixMinusMaxNumMergeCandPlus1                   ( m_PPSSixMinusMaxNumMergeCandPlus1 );
+#if !JVET_Q0806
   m_cEncLib.setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1    ( m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 );
+#else
+  m_cEncLib.setPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1    ( m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 );
+#endif
   m_cEncLib.setUseScalingListId                                  ( m_useScalingListId  );
   m_cEncLib.setScalingListFileName                               ( m_scalingListFileName );
   m_cEncLib.setDisableScalingMatrixForLfnstBlks                  ( m_disableScalingMatrixForLfnstBlks);
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 44cfdba40c9883e77cdcac874b7d36ba4ea3d8f3..e21caa1c7b2656647f70e3f18cc908441507512e 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -104,7 +104,11 @@ EncAppCfg::EncAppCfg()
 , m_noIbcConstraintFlag(false)
 , m_bNoCiipConstraintFlag(false)
 , m_noFPelMmvdConstraintFlag(false)
+#if !JVET_Q0806
 , m_bNoTriangleConstraintFlag(false)
+#else
+, m_noGeoConstraintFlag(false)
+#endif
 , m_bNoLadfConstraintFlag(false)
 , m_noTransformSkipConstraintFlag(false)
 , m_noBDPCMConstraintFlag(false)
@@ -925,7 +929,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("LadfIntervalLowerBound",                          cfg_LadfIntervalLowerBound,  cfg_LadfIntervalLowerBound, "LADF lower bound for 2nd lowest interval")
 #endif
   ("CIIP",                                            m_ciip,                                           false, "Enable CIIP mode")
+#if !JVET_Q0806
   ("Triangle",                                        m_Triangle,                                       false, "Enable triangular shape motion vector prediction (0:off, 1:on)")
+#else
+  ("Geo",                                             m_Geo,                                            false, "Enable geometric partitioning mode (0:off, 1:on)")
+#endif
   ("HashME",                                          m_HashME,                                         false, "Enable hash motion estimation (0:off, 1:on)")
 
   ("AllowDisFracMMVD",                                m_allowDisFracMMVD,                               false, "Disable fractional MVD in MMVD mode adaptively")
@@ -1147,7 +1155,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("SignHideFlag,-SBH",                               m_signDataHidingEnabledFlag,                                    false,  "Enable sign hiding" )
   ("MaxNumMergeCand",                                 m_maxNumMergeCand,                                   5u, "Maximum number of merge candidates")
   ("MaxNumAffineMergeCand",                           m_maxNumAffineMergeCand,                             5u, "Maximum number of affine merge candidates")
+#if !JVET_Q0806
   ("MaxNumTriangleCand",                              m_maxNumTriangleCand,                                5u, "Maximum number of triangle candidates")
+#else
+  ("MaxNumGeoCand",                                   m_maxNumGeoCand,                                     5u, "Maximum number of geometric partitioning mode candidates")
+#endif
   ("MaxNumIBCMergeCand",                              m_maxNumIBCMergeCand,                                6u, "Maximum number of IBC merge candidates")
     /* Misc. */
   ("SEIDecodedPictureHash,-dph",                      tmpDecodedPictureHashSEIMappedType,                   0, "Control generation of decode picture hash SEI messages\n"
@@ -2523,9 +2535,15 @@ bool EncAppCfg::xCheckParameter()
   xConfirmPara( m_log2MaxTbSize < 5,  "Log2MaxTbSize must be 5 or greater." );
   xConfirmPara( m_maxNumMergeCand < 1,  "MaxNumMergeCand must be 1 or greater.");
   xConfirmPara( m_maxNumMergeCand > MRG_MAX_NUM_CANDS, "MaxNumMergeCand must be no more than MRG_MAX_NUM_CANDS." );
+#if !JVET_Q0806
   xConfirmPara( m_maxNumTriangleCand > TRIANGLE_MAX_NUM_UNI_CANDS, "MaxNumTriangleCand must be no more than TRIANGLE_MAX_NUM_UNI_CANDS." );
   xConfirmPara( m_maxNumTriangleCand > m_maxNumMergeCand, "MaxNumTriangleCand must be no more than MaxNumMergeCand." );
   xConfirmPara( 0 < m_maxNumTriangleCand && m_maxNumTriangleCand < 2, "MaxNumTriangleCand must be no less than 2 unless MaxNumTriangleCand is 0." );
+#else
+  xConfirmPara( m_maxNumGeoCand > GEO_MAX_NUM_UNI_CANDS, "MaxNumGeoCand must be no more than GEO_MAX_NUM_UNI_CANDS." );
+  xConfirmPara( m_maxNumGeoCand > m_maxNumMergeCand, "MaxNumGeoCand must be no more than MaxNumMergeCand." );
+  xConfirmPara( 0 < m_maxNumGeoCand && m_maxNumGeoCand < 2, "MaxNumGeoCand must be no less than 2 unless MaxNumGeoCand is 0." );
+#endif
   xConfirmPara( m_maxNumIBCMergeCand < 1, "MaxNumIBCMergeCand must be 1 or greater." );
   xConfirmPara( m_maxNumIBCMergeCand > IBC_MRG_MAX_NUM_CANDS, "MaxNumIBCMergeCand must be no more than IBC_MRG_MAX_NUM_CANDS." );
   xConfirmPara( m_maxNumAffineMergeCand < 1, "MaxNumAffineMergeCand must be 1 or greater." );
@@ -3273,7 +3291,11 @@ bool EncAppCfg::xCheckParameter()
     m_PPSMvdL1ZeroIdc = 0;
     m_PPSCollocatedFromL0Idc = 0;
     m_PPSSixMinusMaxNumMergeCandPlus1 = 0;
+#if !JVET_Q0806
     m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 = 0;
+#else
+    m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 = 0;
+#endif
     break;
   case 1: // RA setting
     m_constantSliceHeaderParamsEnabledFlag = 1;
@@ -3283,7 +3305,11 @@ bool EncAppCfg::xCheckParameter()
     m_PPSMvdL1ZeroIdc = 0;
     m_PPSCollocatedFromL0Idc = 0;
     m_PPSSixMinusMaxNumMergeCandPlus1 = 6 - m_maxNumMergeCand + 1;
+#if !JVET_Q0806
     m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 = m_maxNumMergeCand - m_maxNumTriangleCand + 1;
+#else
+    m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 = m_maxNumMergeCand - m_maxNumGeoCand + 1;
+#endif
     break;
   case 2: // LDB setting
     m_constantSliceHeaderParamsEnabledFlag = 1;
@@ -3293,7 +3319,11 @@ bool EncAppCfg::xCheckParameter()
     m_PPSMvdL1ZeroIdc = 2;
     m_PPSCollocatedFromL0Idc = 1;
     m_PPSSixMinusMaxNumMergeCandPlus1 = 6 - m_maxNumMergeCand + 1;
+#if !JVET_Q0806
     m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 = m_maxNumMergeCand - m_maxNumTriangleCand + 1;
+#else
+    m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 = m_maxNumMergeCand - m_maxNumGeoCand + 1;
+#endif
     break;
   case 3: // LDP setting
     m_constantSliceHeaderParamsEnabledFlag = 1;
@@ -3303,7 +3333,11 @@ bool EncAppCfg::xCheckParameter()
     m_PPSMvdL1ZeroIdc = 0;
     m_PPSCollocatedFromL0Idc = 0;
     m_PPSSixMinusMaxNumMergeCandPlus1 = 6 - m_maxNumMergeCand + 1;
+#if !JVET_Q0806
     m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 = 0;
+#else
+    m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 = 0;
+#endif
     break;
   default:
     THROW("Invalid value for PPSorSliceMode");
@@ -3598,7 +3632,11 @@ void EncAppCfg::xPrintParameter()
 
   msg( DETAILS, "Max Num Merge Candidates               : %d\n", m_maxNumMergeCand );
   msg( DETAILS, "Max Num Affine Merge Candidates        : %d\n", m_maxNumAffineMergeCand );
+#if !JVET_Q0806
   msg( DETAILS, "Max Num Triangle Merge Candidates      : %d\n", m_maxNumTriangleCand );
+#else
+  msg( DETAILS, "Max Num Geo Merge Candidates           : %d\n", m_maxNumGeoCand );
+#endif
   msg( DETAILS, "Max Num IBC Merge Candidates           : %d\n", m_maxNumIBCMergeCand );
   msg( DETAILS, "\n");
 
@@ -3675,7 +3713,11 @@ void EncAppCfg::xPrintParameter()
     msg( VERBOSE, "LADF:%d ", m_LadfEnabed );
 #endif
     msg(VERBOSE, "CIIP:%d ", m_ciip);
+#if !JVET_Q0806
     msg( VERBOSE, "Triangle:%d ", m_Triangle );
+#else
+    msg( VERBOSE, "Geo:%d ", m_Geo );
+#endif
     m_allowDisFracMMVD = m_MMVD ? m_allowDisFracMMVD : false;
     if ( m_MMVD )
       msg(VERBOSE, "AllowDisFracMMVD:%d ", m_allowDisFracMMVD);
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 73559591cc37743aef0c2b9e523b944e3dbe5696..247379852806b35742d1f769e4d178602c867c9d 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -157,7 +157,11 @@ protected:
   bool      m_noIbcConstraintFlag;
   bool      m_bNoCiipConstraintFlag;
   bool      m_noFPelMmvdConstraintFlag;
+#if !JVET_Q0806
   bool      m_bNoTriangleConstraintFlag;
+#else
+  bool      m_noGeoConstraintFlag;
+#endif
   bool      m_bNoLadfConstraintFlag;
   bool      m_noTransformSkipConstraintFlag;
   bool      m_noBDPCMConstraintFlag;
@@ -311,7 +315,11 @@ protected:
 #endif
 
   bool      m_ciip;
+#if !JVET_Q0806
   bool      m_Triangle;
+#else
+  bool      m_Geo;
+#endif
   bool      m_HashME;
   bool      m_allowDisFracMMVD;
   bool      m_AffineAmvr;
@@ -592,7 +600,11 @@ protected:
 #endif
   uint32_t      m_maxNumMergeCand;                                ///< Max number of merge candidates
   uint32_t      m_maxNumAffineMergeCand;                          ///< Max number of affine merge candidates
+#if !JVET_Q0806
   uint32_t      m_maxNumTriangleCand;
+#else
+  uint32_t      m_maxNumGeoCand;
+#endif
   uint32_t      m_maxNumIBCMergeCand;                             ///< Max number of IBC merge candidates
 
   bool      m_sliceLevelRpl;                                      ///< code reference picture lists in slice headers rather than picture header
@@ -608,7 +620,11 @@ protected:
   int       m_PPSMvdL1ZeroIdc;
   int       m_PPSCollocatedFromL0Idc;
   uint32_t  m_PPSSixMinusMaxNumMergeCandPlus1;
+#if !JVET_Q0806
   uint32_t  m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1;
+#else
+  uint32_t  m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1;
+#endif
   bool      m_depQuantEnabledFlag;
   bool      m_signDataHidingEnabledFlag;
   bool      m_RCEnableRateControl;                ///< enable rate control or not
diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
index b1ef4b056c62ed8c62b353fd8829ad0cf7703eeb..4d862ff95008c1b7543b0f1d53f480f329e066ea 100644
--- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
+++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
@@ -294,20 +294,16 @@ void AdaptiveLoopFilter::applyCcAlfFilter(CodingStructure &cs, ComponentID compI
                                           const short filterSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF],
                                           const int   selectedFilterIdx)
 {
+  bool clipTop = false, clipBottom = false, clipLeft = false, clipRight = false;
+  int  numHorVirBndry = 0, numVerVirBndry = 0;
+  int  horVirBndryPos[] = { 0, 0, 0 };
+  int  verVirBndryPos[] = { 0, 0, 0 };
+
   int ctuIdx = 0;
   for( int yPos = 0; yPos < m_picHeight; yPos += m_maxCUHeight )
   {
     for( int xPos = 0; xPos < m_picWidth; xPos += m_maxCUWidth )
     {
-      const int width = ( xPos + m_maxCUWidth > m_picWidth ) ? ( m_picWidth - xPos ) : m_maxCUWidth;
-      const int height = ( yPos + m_maxCUHeight > m_picHeight ) ? ( m_picHeight - yPos ) : m_maxCUHeight;
-      const UnitArea area( m_chromaFormat, Area( xPos, yPos, width, height ) );
-      const int chromaScaleX = getComponentScaleX( compID, m_chromaFormat );
-      const int chromaScaleY = getComponentScaleY( compID, m_chromaFormat );
-
-      Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY);
-      Area blkSrc(xPos, yPos, width, height);
-
       int filterIdx =
         (filterControl == nullptr)
           ? selectedFilterIdx
@@ -320,8 +316,73 @@ void AdaptiveLoopFilter::applyCcAlfFilter(CodingStructure &cs, ComponentID compI
 
         const int16_t *filterCoeff = filterSet[filterIdx];
 
-        m_filterCcAlf(dstBuf, recYuvExt, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight,
-                      m_alfVBLumaPos);
+        const int width        = (xPos + m_maxCUWidth > m_picWidth) ? (m_picWidth - xPos) : m_maxCUWidth;
+        const int height       = (yPos + m_maxCUHeight > m_picHeight) ? (m_picHeight - yPos) : m_maxCUHeight;
+        const int chromaScaleX = getComponentScaleX(compID, m_chromaFormat);
+        const int chromaScaleY = getComponentScaleY(compID, m_chromaFormat);
+
+        int rasterSliceAlfPad = 0;
+        if (isCrossedByVirtualBoundaries(cs, xPos, yPos, width, height, clipTop, clipBottom, clipLeft, clipRight,
+                                         numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos,
+                                         rasterSliceAlfPad))
+        {
+          int yStart = yPos;
+          for (int i = 0; i <= numHorVirBndry; i++)
+          {
+            const int  yEnd   = i == numHorVirBndry ? yPos + height : horVirBndryPos[i];
+            const int  h      = yEnd - yStart;
+            const bool clipT  = (i == 0 && clipTop) || (i > 0) || (yStart == 0);
+            const bool clipB  = (i == numHorVirBndry && clipBottom) || (i < numHorVirBndry) || (yEnd == m_picHeight);
+            int        xStart = xPos;
+            for (int j = 0; j <= numVerVirBndry; j++)
+            {
+              const int  xEnd  = j == numVerVirBndry ? xPos + width : verVirBndryPos[j];
+              const int  w     = xEnd - xStart;
+              const bool clipL = (j == 0 && clipLeft) || (j > 0) || (xStart == 0);
+              const bool clipR = (j == numVerVirBndry && clipRight) || (j < numVerVirBndry) || (xEnd == m_picWidth);
+              const int  wBuf  = w + (clipL ? 0 : MAX_ALF_PADDING_SIZE) + (clipR ? 0 : MAX_ALF_PADDING_SIZE);
+              const int  hBuf  = h + (clipT ? 0 : MAX_ALF_PADDING_SIZE) + (clipB ? 0 : MAX_ALF_PADDING_SIZE);
+              PelUnitBuf buf   = m_tempBuf2.subBuf(UnitArea(cs.area.chromaFormat, Area(0, 0, wBuf, hBuf)));
+              buf.copyFrom(recYuvExt.subBuf(
+                UnitArea(cs.area.chromaFormat, Area(xStart - (clipL ? 0 : MAX_ALF_PADDING_SIZE),
+                                                    yStart - (clipT ? 0 : MAX_ALF_PADDING_SIZE), wBuf, hBuf))));
+              // pad top-left unavailable samples for raster slice
+              if (xStart == xPos && yStart == yPos && (rasterSliceAlfPad & 1))
+              {
+                buf.padBorderPel(MAX_ALF_PADDING_SIZE, 1);
+              }
+
+              // pad bottom-right unavailable samples for raster slice
+              if (xEnd == xPos + width && yEnd == yPos + height && (rasterSliceAlfPad & 2))
+              {
+                buf.padBorderPel(MAX_ALF_PADDING_SIZE, 2);
+              }
+              buf.extendBorderPel(MAX_ALF_PADDING_SIZE);
+              buf = buf.subBuf(UnitArea(
+                cs.area.chromaFormat, Area(clipL ? 0 : MAX_ALF_PADDING_SIZE, clipT ? 0 : MAX_ALF_PADDING_SIZE, w, h)));
+
+              const Area blkSrc(0, 0, w, h);
+
+              const Area blkDst(xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY);
+              m_filterCcAlf(dstBuf, buf, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight,
+                            m_alfVBLumaPos);
+
+              xStart = xEnd;
+            }
+
+            yStart = yEnd;
+          }
+        }
+        else
+        {
+          const UnitArea area(m_chromaFormat, Area(xPos, yPos, width, height));
+
+          Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY);
+          Area blkSrc(xPos, yPos, width, height);
+
+          m_filterCcAlf(dstBuf, recYuvExt, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight,
+                        m_alfVBLumaPos);
+        }
       }
       ctuIdx++;
     }
@@ -474,13 +535,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs)
 
                 if (filterIdx != 0)
                 {
-                  const Area blkSrc(0, 0, w >> chromaScaleX, h >> chromaScaleY);
-                  Area       blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX,
-                              height >> chromaScaleY);
+                  const Area blkSrc(0, 0, w, h);
+                  Area blkDst(xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY);
 
                   const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1];
 
-                  m_filterCcAlf(recYuv.get(compID), tmpYuv, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs,
+                  m_filterCcAlf(recYuv.get(compID), buf, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs,
                                 m_alfVBLumaCTUHeight, m_alfVBLumaPos);
                 }
               }
diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp
index 8320dbe7c8ae76e93689d0b7b581b5681bd9696d..7b59a40e88aaed51824cbecb6fa4f7aae3a9e1b4 100644
--- a/source/Lib/CommonLib/Buffer.cpp
+++ b/source/Lib/CommonLib/Buffer.cpp
@@ -553,6 +553,38 @@ void AreaBuf<Pel>::copyClip( const AreaBuf<const Pel> &src, const ClpRng& clpRng
   }
 }
 
+#if JVET_Q0806
+template<>
+void AreaBuf<Pel>::roundToOutputBitdepth( const AreaBuf<const Pel> &src, const ClpRng& clpRng )
+{
+  const Pel* srcp = src.buf;
+        Pel* dest =     buf;
+  const unsigned srcStride  = src.stride;
+  const unsigned destStride = stride;
+
+  const int32_t clipbd            = clpRng.bd;
+  const int32_t shiftDefault      = std::max<int>(2, (IF_INTERNAL_PREC - clipbd));
+  const int32_t offsetDefault     = (1<<(shiftDefault-1)) + IF_INTERNAL_OFFS;
+   
+  if( width == 1 )
+  {
+    THROW( "Blocks of width = 1 not supported" );
+  }
+  else
+  {
+#define RND_OP( ADDR ) dest[ADDR] = ClipPel( rightShift( srcp[ADDR] + offsetDefault, shiftDefault), clpRng )
+#define RND_INC        \
+    srcp += srcStride;  \
+    dest += destStride; \
+
+    SIZE_AWARE_PER_EL_OP( RND_OP, RND_INC );
+
+#undef RND_OP
+#undef RND_INC
+  }
+}
+#endif
+
 
 template<>
 void AreaBuf<Pel>::reconstruct( const AreaBuf<const Pel> &pred, const AreaBuf<const Pel> &resi, const ClpRng& clpRng )
diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h
index 0fbd97a5edcceb94333a08174c9ad91a48e0a555..fa72565ba5dcf5e4ebeac4fd2bfaca4d7593accc 100644
--- a/source/Lib/CommonLib/Buffer.h
+++ b/source/Lib/CommonLib/Buffer.h
@@ -110,6 +110,9 @@ struct AreaBuf : public Size
   void memset               ( const int val );
 
   void copyFrom             ( const AreaBuf<const T> &other );
+#if JVET_Q0806
+  void roundToOutputBitdepth(const AreaBuf<const T> &src, const ClpRng& clpRng);
+#endif
 
   void reconstruct          ( const AreaBuf<const T> &pred, const AreaBuf<const T> &resi, const ClpRng& clpRng);
   void copyClip             ( const AreaBuf<const T> &src, const ClpRng& clpRng);
@@ -764,6 +767,9 @@ struct UnitBuf
 
   void fill                 ( const T &val );
   void copyFrom             ( const UnitBuf<const T> &other, const bool lumaOnly = false, const bool chromaOnly = false );
+#if JVET_Q0806
+  void roundToOutputBitdepth(const UnitBuf<const T> &src, const ClpRngs& clpRngs);
+#endif
   void reconstruct          ( const UnitBuf<const T> &pred, const UnitBuf<const T> &resi, const ClpRngs& clpRngs );
   void copyClip             ( const UnitBuf<const T> &src, const ClpRngs& clpRngs, const bool lumaOnly = false, const bool chromaOnly = false );
   void subtract             ( const UnitBuf<const T> &other );
@@ -843,6 +849,19 @@ void UnitBuf<T>::copyClip(const UnitBuf<const T> &src, const ClpRngs &clpRngs, c
 }
 
 
+#if JVET_Q0806
+template<typename T>
+void UnitBuf<T>::roundToOutputBitdepth(const UnitBuf<const T> &src, const ClpRngs& clpRngs)
+{
+  CHECK(chromaFormat != src.chromaFormat, "Incompatible formats");
+
+  for (unsigned i = 0; i < bufs.size(); i++)
+  {
+    bufs[i].roundToOutputBitdepth(src.bufs[i], clpRngs.comp[i]);
+  }
+}
+#endif
+
 template<typename T>
 void UnitBuf<T>::reconstruct(const UnitBuf<const T> &pred, const UnitBuf<const T> &resi, const ClpRngs& clpRngs)
 {
diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h
index 59b610717e1fd61074fa6cb2c88217775b98f38b..7c0ad7af7ecca5b2bb650e9045a49bdbe4acd933 100644
--- a/source/Lib/CommonLib/CodingStatistics.h
+++ b/source/Lib/CommonLib/CodingStatistics.h
@@ -112,8 +112,13 @@ enum CodingStatisticsType
   STATS__CABAC_BITS__BCW_IDX,
   STATS__CABAC_BITS__SBT_MODE,
   STATS__CABAC_BITS__MH_INTRA_FLAG,
+#if !JVET_Q0806
   STATS__CABAC_BITS__TRIANGLE_FLAG,
   STATS__CABAC_BITS__TRIANGLE_INDEX,
+#else
+  STATS__CABAC_BITS__GEO_FLAG,
+  STATS__CABAC_BITS__GEO_INDEX,
+#endif
   STATS__CABAC_BITS__MULTI_REF_LINE,
   STATS__CABAC_BITS__SYMMVD_FLAG,
   STATS__CABAC_BITS__BDPCM_MODE,
@@ -207,8 +212,13 @@ static inline const char* getName(CodingStatisticsType name)
     "CABAC_BITS__BCW_IDX",
     "CABAC_BITS__SBT_MODE",
     "CABAC_BITS__MH_INTRA_FLAG",
+#if !JVET_Q0806
     "CABAC_BITS__TRIANGLE_FLAG",
     "CABAC_BITS__TRIANGLE_INDEX",
+#else
+    "CABAC_BITS__GEO_FLAG",
+    "CABAC_BITS__GEO_INDEX",
+#endif
     "CABAC_BITS__MULTI_REF_LINE",
     "CABAC_BITS__SYMMVD_FLAG",
     "CABAC_BITS__BDPCM_MODE",
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index fb83cf5b8b4b13bc96acbccc099206c2aa30b324..4f1864b5f21ee9cd9fb760c1feed4ece53561611 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -427,11 +427,29 @@ static const int MAX_LADF_INTERVALS       =                         5; /// max n
 static const int NTAPS_BILINEAR           =                         2; ///< Number of taps for bilinear filter
 
 static const int ATMVP_SUB_BLOCK_SIZE =                             3; ///< sub-block size for ATMVP
+#if !JVET_Q0806
 static const int TRIANGLE_MAX_NUM_UNI_CANDS =                       6;
 static const int TRIANGLE_MAX_NUM_CANDS_MEM =                       7;
 static const int TRIANGLE_MAX_NUM_CANDS = TRIANGLE_MAX_NUM_UNI_CANDS * (TRIANGLE_MAX_NUM_UNI_CANDS - 1) * 2;
 static const int TRIANGLE_MAX_NUM_SATD_CANDS =                      3;
 static const int TRIANGLE_MIN_SIZE =                            8 * 8;
+#else
+static const int GEO_MAX_NUM_UNI_CANDS =                            6;
+static const int GEO_MAX_NUM_CANDS = GEO_MAX_NUM_UNI_CANDS * (GEO_MAX_NUM_UNI_CANDS - 1);
+static const int GEO_MIN_CU_LOG2 =                                  3;
+static const int GEO_MAX_CU_LOG2 =                                  6;
+static const int GEO_MIN_CU_SIZE =               1 << GEO_MIN_CU_LOG2;
+static const int GEO_MAX_CU_SIZE =               1 << GEO_MAX_CU_LOG2;
+static const int GEO_NUM_CU_SIZE = ( GEO_MAX_CU_LOG2 - GEO_MIN_CU_LOG2 ) + 1;
+static const int GEO_NUM_PARTITION_MODE =                          64;
+static const int GEO_NUM_ANGLES =                                  32;
+static const int GEO_NUM_DISTANCES =                                4;
+static const int GEO_NUM_PRESTORED_MASK =                           6;
+static const int GEO_WEIGHT_MASK_SIZE = 3 * (GEO_MAX_CU_SIZE >> 3) * 2 + GEO_MAX_CU_SIZE;
+static const int GEO_MV_MASK_SIZE =         GEO_WEIGHT_MASK_SIZE >> 2;
+static const int GEO_MAX_TRY_WEIGHTED_SAD = 60;
+static const int GEO_MAX_TRY_WEIGHTED_SATD = 8;
+#endif
 
 static const int SBT_MAX_SIZE =                                    64; ///< maximum CU size for using SBT
 static const int SBT_NUM_SL =                                      10; ///< maximum number of historical PU decision saved for a CU
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index a8cd73368084658fcad816d2629de404833d639a..6913c4d54f3075d930bc7a96a4922abc5a106e12 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -320,11 +320,19 @@ unsigned DeriveCtx::CtxIBCFlag(const CodingUnit& cu)
 void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
 {
   CHECK( candIdx >= numValidMergeCand, "Merge candidate does not exist" );
+#if !JVET_Q0806
   pu.regularMergeFlag        = !(pu.ciipFlag || pu.cu->triangle);
+#else
+  pu.regularMergeFlag        = !(pu.ciipFlag || pu.cu->geoFlag);
+#endif
   pu.mergeFlag               = true;
   pu.mmvdMergeFlag = false;
   pu.interDir                = interDirNeighbours[candIdx];
+#if !JVET_Q0806
   pu.cu->imv = (!pu.cu->triangle && useAltHpelIf[candIdx]) ? IMV_HPEL : 0;
+#else
+  pu.cu->imv = (!pu.cu->geoFlag && useAltHpelIf[candIdx]) ? IMV_HPEL : 0;
+#endif
   pu.mergeIdx                = candIdx;
   pu.mergeType               = mrgTypeNeighbours[candIdx];
   pu.mv     [REF_PIC_LIST_0] = mvFieldNeighbours[(candIdx << 1) + 0].mv;
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index d749d78e90b73f8a2d74bff6661b3d1e2faf79da..ab4a35f8d3ab128b876e3de87312cc35b567260c 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -126,7 +126,12 @@ void InterPrediction::destroy()
     }
   }
 
+#if !JVET_Q0806
   m_triangleBuf.destroy();
+#else
+  m_geoPartBuf[0].destroy();
+  m_geoPartBuf[1].destroy();
+#endif
   m_colorTransResiBuf[0].destroy();
   m_colorTransResiBuf[1].destroy();
   m_colorTransResiBuf[2].destroy();
@@ -192,7 +197,12 @@ void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC, cons
       }
     }
 
+#if !JVET_Q0806
     m_triangleBuf.create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+#else
+    m_geoPartBuf[0].create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+    m_geoPartBuf[1].create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+#endif
     m_colorTransResiBuf[0].create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
     m_colorTransResiBuf[1].create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
     m_colorTransResiBuf[2].create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
@@ -629,7 +639,11 @@ void InterPrediction::xPredInterBi(PredictionUnit &pu, PelUnitBuf &pcYuvPred, co
       }
       else
       {
+#if !JVET_Q0806
         xPredInterUni( pu, eRefPicList, pcMbBuf, pu.cu->triangle
+#else
+        xPredInterUni(pu, eRefPicList, pcMbBuf, pu.cu->geoFlag
+#endif
           , bioApplied
           , luma, chroma
         );
@@ -644,13 +658,21 @@ void InterPrediction::xPredInterBi(PredictionUnit &pu, PelUnitBuf &pcYuvPred, co
                            CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[1][0], pcYuvPred.Y()), PelBuf(m_acYuvPred[1][1], pcYuvPred.Cb()), PelBuf(m_acYuvPred[1][2], pcYuvPred.Cr())) );
   const bool lumaOnly   = luma && !chroma;
   const bool chromaOnly = !luma && chroma;
+#if !JVET_Q0806  
   if( !pu.cu->triangle && (!dmvrApplied) && (!bioApplied) && pps.getWPBiPred() && slice.getSliceType() == B_SLICE && pu.cu->BcwIdx==BCW_DEFAULT)
+#else
+  if( !pu.cu->geoFlag && (!dmvrApplied) && (!bioApplied) && pps.getWPBiPred() && slice.getSliceType() == B_SLICE && pu.cu->BcwIdx == BCW_DEFAULT)
+#endif
   {
     xWeightedPredictionBi( pu, srcPred0, srcPred1, pcYuvPred, m_maxCompIDToPred, lumaOnly, chromaOnly );
     if (yuvPredTmp)
       yuvPredTmp->copyFrom(pcYuvPred);
   }
+#if !JVET_Q0806
   else if( !pu.cu->triangle && pps.getUseWP() && slice.getSliceType() == P_SLICE )
+#else
+  else if( !pu.cu->geoFlag && pps.getUseWP() && slice.getSliceType() == P_SLICE )
+#endif
   {
     xWeightedPredictionUni( pu, srcPred0, REF_PIC_LIST_0, pcYuvPred, -1, m_maxCompIDToPred, lumaOnly, chromaOnly );
     if (yuvPredTmp)
@@ -1453,22 +1475,38 @@ void InterPrediction::xWeightedAverage(const PredictionUnit& pu, const CPelUnitB
   }
   else if( iRefIdx0 >= 0 && iRefIdx1 < 0 )
   {
+#if !JVET_Q0806
     if( pu.cu->triangle )
     {
       pcYuvDst.copyFrom( pcYuvSrc0 );
     }
     else
+#else
+    if( pu.cu->geoFlag )
+    {
+      pcYuvDst.copyFrom( pcYuvSrc0 );
+    }
+    else
+#endif
       pcYuvDst.copyClip( pcYuvSrc0, clpRngs, lumaOnly, chromaOnly );
     if (yuvDstTmp)
       yuvDstTmp->copyFrom( pcYuvDst, lumaOnly, chromaOnly );
   }
   else if( iRefIdx0 < 0 && iRefIdx1 >= 0 )
   {
+#if !JVET_Q0806
     if( pu.cu->triangle )
     {
       pcYuvDst.copyFrom( pcYuvSrc1 );
     }
     else
+#else
+    if( pu.cu->geoFlag )
+    {
+      pcYuvDst.copyFrom( pcYuvSrc1 );
+    }
+    else
+#endif
       pcYuvDst.copyClip( pcYuvSrc1, clpRngs, lumaOnly, chromaOnly );
     if (yuvDstTmp)
       yuvDstTmp->copyFrom(pcYuvDst, lumaOnly, chromaOnly);
@@ -1655,6 +1693,7 @@ int InterPrediction::rightShiftMSB(int numer, int denom)
   return numer >> floorLog2(denom);
 }
 
+#if !JVET_Q0806
 void InterPrediction::motionCompensation4Triangle( CodingUnit &cu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1 )
 {
   for( auto &pu : CU::traversePUs( cu ) )
@@ -1706,7 +1745,57 @@ void InterPrediction::weightedTriangleBlk( PredictionUnit &pu, const bool splitD
     m_if.weightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1 );
   }
 }
+#else
+void InterPrediction::motionCompensationGeo( CodingUnit &cu, MergeCtx &geoMrgCtx )
+{
+  const uint8_t splitDir = cu.firstPU->geoSplitDir;
+  const uint8_t candIdx0 = cu.firstPU->geoMergeIdx0;
+  const uint8_t candIdx1 = cu.firstPU->geoMergeIdx1;
+  for( auto &pu : CU::traversePUs( cu ) )
+  {
+    const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, pu.lwidth(), pu.lheight() ) );
+    PelUnitBuf tmpGeoBuf0 = m_geoPartBuf[0].getBuf( localUnitArea );
+    PelUnitBuf tmpGeoBuf1 = m_geoPartBuf[1].getBuf( localUnitArea );
+    PelUnitBuf predBuf    = cu.cs->getPredBuf( pu );
+
+    geoMrgCtx.setMergeInfo( pu, candIdx0 );
+    PU::spanMotionInfo( pu );
+    motionCompensation(pu, tmpGeoBuf0, REF_PIC_LIST_X, true, isChromaEnabled(pu.chromaFormat));
+    if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
+    {
+      printf( "DECODER_GEO_PU: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+    }
+    
+    geoMrgCtx.setMergeInfo( pu, candIdx1 );
+    PU::spanMotionInfo( pu );
+    motionCompensation(pu, tmpGeoBuf1, REF_PIC_LIST_X, true, isChromaEnabled(pu.chromaFormat));
+    if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
+    {
+      printf( "DECODER_GEO_PU: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+    }
+    weightedGeoBlk(pu, splitDir, isChromaEnabled(pu.chromaFormat)? MAX_NUM_CHANNEL_TYPE : CHANNEL_TYPE_LUMA, predBuf, tmpGeoBuf0, tmpGeoBuf1);
+  }
+}
 
+void InterPrediction::weightedGeoBlk( PredictionUnit &pu, const uint8_t splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
+{
+  if( channel == CHANNEL_TYPE_LUMA )
+  {
+    m_if.weightedGeoBlk( pu, pu.lumaSize().width, pu.lumaSize().height, COMPONENT_Y, splitDir, predDst, predSrc0, predSrc1 );
+  }
+  else if( channel == CHANNEL_TYPE_CHROMA )
+  {
+    m_if.weightedGeoBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1 );
+    m_if.weightedGeoBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1 );
+  }
+  else
+  {
+    m_if.weightedGeoBlk( pu, pu.lumaSize().width,   pu.lumaSize().height,   COMPONENT_Y,  splitDir, predDst, predSrc0, predSrc1 );
+    m_if.weightedGeoBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1 );
+    m_if.weightedGeoBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1 );
+  }
+}
+#endif
 
 void InterPrediction::xPrefetch(PredictionUnit& pu, PelUnitBuf &pcPad, RefPicList refId, bool forLuma)
 {
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 1bc16ff8d7b567029f5eaff532713e6f850cb822..a7455d46186a691fddb8ec20d96a67a12b29a729 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -81,7 +81,11 @@ protected:
   RdCost*              m_pcRdCost;
 
   int                  m_iRefListIdx;
+#if !JVET_Q0806
   PelStorage           m_triangleBuf;
+#else
+  PelStorage           m_geoPartBuf[2];
+#endif
   Mv*                  m_storedMv;
  /*buffers for bilinear Filter data for DMVR refinement*/
   Pel*                 m_cYuvPredTempDMVRL0;
@@ -138,7 +142,9 @@ protected:
   void xCalcBlkGradient         (int sx, int sy, int    *arraysGx2, int     *arraysGxGy, int     *arraysGxdI, int     *arraysGy2, int     *arraysGydI, int     &sGx2, int     &sGy2, int     &sGxGy, int     &sGxdI, int     &sGydI, int width, int height, int unitSize);
   void xWeightedAverage         ( const PredictionUnit& pu, const CPelUnitBuf& pcYuvSrc0, const CPelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const BitDepths& clipBitDepths, const ClpRngs& clpRngs, const bool& bioApplied, const bool lumaOnly = false, const bool chromaOnly = false, PelUnitBuf* yuvDstTmp = NULL );
   void xPredAffineBlk           ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv* _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng, const bool genChromaMv = false, const std::pair<int, int> scalingRatio = SCALE_1X );
+#if !JVET_Q0806
   void xWeightedTriangleBlk     ( const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 );
+#endif
 
   static bool xCheckIdenticalMotion( const PredictionUnit& pu );
 
@@ -171,8 +177,13 @@ public:
     , const bool luma = true, const bool chroma = true
   );
 
+#if !JVET_Q0806
   void    motionCompensation4Triangle( CodingUnit &cu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1 );
   void    weightedTriangleBlk        ( PredictionUnit &pu, const bool splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 );
+#else
+  void    motionCompensationGeo(CodingUnit &cu, MergeCtx &GeoMrgCtx);
+  void    weightedGeoBlk(PredictionUnit &pu, const uint8_t splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
+#endif
   void xPrefetch(PredictionUnit& pu, PelUnitBuf &pcPad, RefPicList refId, bool forLuma);
   void xPad(PredictionUnit& pu, PelUnitBuf &pcPad, RefPicList refId);
   void xFinalPaddedMCForDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvSrc0, PelUnitBuf &pcYuvSrc1, PelUnitBuf &pcPad0, PelUnitBuf &pcPad1, const bool bioApplied
diff --git a/source/Lib/CommonLib/InterpolationFilter.cpp b/source/Lib/CommonLib/InterpolationFilter.cpp
index 77f46edcaef115d526d647209de596b041790405..5fb66c384000e6eb3a174233326180ed17e118c3 100644
--- a/source/Lib/CommonLib/InterpolationFilter.cpp
+++ b/source/Lib/CommonLib/InterpolationFilter.cpp
@@ -371,7 +371,11 @@ InterpolationFilter::InterpolationFilter()
   m_filterCopy[1][0]   = filterCopy<true, false>;
   m_filterCopy[1][1]   = filterCopy<true, true>;
 
+#if !JVET_Q0806
   m_weightedTriangleBlk = xWeightedTriangleBlk;
+#else
+  m_weightedGeoBlk = xWeightedGeoBlk;
+#endif
 }
 
 
@@ -888,6 +892,7 @@ void InterpolationFilter::filterVer(const ComponentID compID, Pel const *src, in
   }
 }
 
+#if !JVET_Q0806
 void InterpolationFilter::xWeightedTriangleBlk( const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 )
 {
   Pel*    dst        = predDst .get(compIdx).buf;
@@ -983,6 +988,65 @@ void InterpolationFilter::weightedTriangleBlk(const PredictionUnit &pu, const ui
 {
   m_weightedTriangleBlk(pu, width, height, compIdx, splitDir, predDst, predSrc0, predSrc1);
 }
+#else
+void InterpolationFilter::weightedGeoBlk(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const uint8_t splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
+{
+  m_weightedGeoBlk(pu, width, height, compIdx, splitDir, predDst, predSrc0, predSrc1);
+}
+
+void InterpolationFilter::xWeightedGeoBlk(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const uint8_t splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
+{
+  Pel*    dst = predDst.get(compIdx).buf;
+  Pel*    src0 = predSrc0.get(compIdx).buf;
+  Pel*    src1 = predSrc1.get(compIdx).buf;
+  int32_t strideDst = predDst.get(compIdx).stride - width;
+  int32_t strideSrc0 = predSrc0.get(compIdx).stride - width;
+  int32_t strideSrc1 = predSrc1.get(compIdx).stride - width;
+
+  const char    log2WeightBase = 3;
+  const ClpRng  clipRng = pu.cu->slice->clpRngs().comp[compIdx];
+  const int32_t clipbd = clipRng.bd;
+  const int32_t shiftWeighted = std::max<int>(2, (IF_INTERNAL_PREC - clipbd)) + log2WeightBase;
+  const int32_t offsetWeighted = (1 << (shiftWeighted - 1)) + (IF_INTERNAL_OFFS << log2WeightBase);
+  const uint32_t scaleX = getComponentScaleX(compIdx, pu.chromaFormat);
+  const uint32_t scaleY = getComponentScaleY(compIdx, pu.chromaFormat);
+
+  int16_t angle = g_GeoParams[splitDir][0];
+  int16_t wIdx = floorLog2(pu.lwidth()) - GEO_MIN_CU_LOG2;
+  int16_t hIdx = floorLog2(pu.lheight()) - GEO_MIN_CU_LOG2;
+  int16_t stepX = 1 << scaleX;
+  int16_t stepY = 0;
+  int16_t* weight = nullptr;
+  if (g_angle2mirror[angle] == 2)
+  {
+    stepY = -(int)((GEO_WEIGHT_MASK_SIZE << scaleY) + pu.lwidth());
+    weight = &g_globalGeoWeights[g_angle2mask[angle]][(GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][1]) * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+  }
+  else if (g_angle2mirror[angle] == 1)
+  {
+    stepX = -1 << scaleX;
+    stepY = (GEO_WEIGHT_MASK_SIZE << scaleY) + pu.lwidth();
+    weight = &g_globalGeoWeights[g_angle2mask[angle]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + (GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][0])];
+  }
+  else
+  {
+    stepY = (GEO_WEIGHT_MASK_SIZE << scaleY) - pu.lwidth();
+    weight = &g_globalGeoWeights[g_angle2mask[angle]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+  }
+  for( int y = 0; y < height; y++ )
+  {
+    for( int x = 0; x < width; x++ )
+    {
+      *dst++  = ClipPel(rightShift((*weight*(*src0++) + ((8 - *weight) * (*src1++)) + offsetWeighted), shiftWeighted), clipRng);
+      weight += stepX;
+    }
+    dst    += strideDst;
+    src0   += strideSrc0;
+    src1   += strideSrc1;
+    weight += stepY;
+  }
+}
+#endif
 
 /**
  * \brief turn on SIMD fuc
diff --git a/source/Lib/CommonLib/InterpolationFilter.h b/source/Lib/CommonLib/InterpolationFilter.h
index db2a0846381e46ac152241b9a7357f64cca8640a..c166395af7ec59bb1e37dad27a2c3436d81e0a96 100644
--- a/source/Lib/CommonLib/InterpolationFilter.h
+++ b/source/Lib/CommonLib/InterpolationFilter.h
@@ -83,8 +83,13 @@ public:
   template<int N>
   void filterVer(const ClpRng& clpRng, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isFirst, bool isLast, TFilterCoeff const *coeff, bool biMCForDMVR);
 
+#if !JVET_Q0806
   static void xWeightedTriangleBlk(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
   void weightedTriangleBlk(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
+#else
+  static void xWeightedGeoBlk(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const uint8_t splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
+  void weightedGeoBlk(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const uint8_t splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
+#endif
 protected:
 #if JVET_J0090_MEMORY_BANDWITH_MEASURE
   static CacheModel* m_cacheModel;
@@ -95,7 +100,11 @@ public:
   void( *m_filterHor[3][2][2] )( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR);
   void( *m_filterVer[3][2][2] )( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR);
   void( *m_filterCopy[2][2] )  ( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool biMCForDMVR);
+#if !JVET_Q0806
   void( *m_weightedTriangleBlk )(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
+#else
+  void( *m_weightedGeoBlk )(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const uint8_t splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1);
+#endif
 
   void initInterpolationFilter( bool enable );
 #ifdef TARGET_SIMD_X86
diff --git a/source/Lib/CommonLib/MatrixIntraPrediction.cpp b/source/Lib/CommonLib/MatrixIntraPrediction.cpp
index f3376aa25da490108aa96b72541b597bebead49c..af6adae25633456c844c2b326f7b96c4badb8d7d 100644
--- a/source/Lib/CommonLib/MatrixIntraPrediction.cpp
+++ b/source/Lib/CommonLib/MatrixIntraPrediction.cpp
@@ -105,8 +105,13 @@ void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area&
   m_inputOffsetTransp = m_reducedBoundaryTransposed[0];
 
   const bool hasFirstCol = (m_sizeId < 2);
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+  m_reducedBoundary          [0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffset      ) : 0; // first column of matrix not needed for large blocks
+  m_reducedBoundaryTransposed[0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffsetTransp) : 0;
+#else
   m_reducedBoundary          [0] = hasFirstCol ? (m_inputOffset       - (1 << (bitDepth - 1))) : 0; // first column of matrix not needed for large blocks
   m_reducedBoundaryTransposed[0] = hasFirstCol ? (m_inputOffsetTransp - (1 << (bitDepth - 1))) : 0;
+#endif
   for (int i = 1; i < inputSize; i++)
   {
     m_reducedBoundary          [i] -= m_inputOffset;
@@ -118,14 +123,22 @@ void MatrixIntraPrediction::predBlock(int* const result, const int modeIdx, cons
 {
   const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );
 
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+  const uint8_t* matrix = getMatrixData(modeIdx);
+#else
   const uint8_t* matrix;
   int shiftMatrix = 0, offsetMatrix = 0;
   getMatrixData(matrix, shiftMatrix, offsetMatrix, modeIdx);
+#endif
 
   static_vector<int, MIP_MAX_REDUCED_OUTPUT_SAMPLES> bufReducedPred( m_reducedPredSize * m_reducedPredSize );
   int* const       reducedPred     = needUpsampling ? bufReducedPred.data() : result;
   const int* const reducedBoundary = transpose ? m_reducedBoundaryTransposed.data() : m_reducedBoundary.data();
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+  computeReducedPred(reducedPred, reducedBoundary, matrix, transpose, bitDepth);
+#else
   computeReducedPred( reducedPred, reducedBoundary, matrix, shiftMatrix, offsetMatrix, transpose, bitDepth );
+#endif
   if( needUpsampling )
   {
     predictionUpsampling( result, reducedPred );
@@ -262,10 +275,21 @@ void MatrixIntraPrediction::predictionUpsampling( int* const dst, const int* con
   }
 }
 
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+const uint8_t* MatrixIntraPrediction::getMatrixData(const int modeIdx) const
+#else
 void MatrixIntraPrediction::getMatrixData(const uint8_t*& matrix, int &shiftMatrix, int &offsetMatrix, const int modeIdx) const
+#endif
 {
   switch( m_sizeId )
   {
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+  case 0: return &mipMatrix4x4[modeIdx][0][0];
+
+  case 1: return &mipMatrix8x8[modeIdx][0][0];
+
+  case 2: return &mipMatrix16x16[modeIdx][0][0];
+#else
   case 0: matrix       = &mipMatrix4x4      [modeIdx][0][0];
           shiftMatrix  =  mipShiftMatrix4x4 [modeIdx];
           offsetMatrix =  mipOffsetMatrix4x4[modeIdx];
@@ -280,13 +304,18 @@ void MatrixIntraPrediction::getMatrixData(const uint8_t*& matrix, int &shiftMatr
           shiftMatrix  =  mipShiftMatrix16x16 [modeIdx];
           offsetMatrix =  mipOffsetMatrix16x16[modeIdx];
           break;
+#endif
 
   default: THROW( "Invalid mipSizeId" );
   }
 }
 
 void MatrixIntraPrediction::computeReducedPred( int*const result, const int* const input, 
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+                                                const uint8_t* matrix,
+#else
                                                 const uint8_t*matrix, const int shiftMatrix, const int offsetMatrix,
+#endif
                                                 const bool transpose, const int bitDepth )
 {
   const int inputSize = 2 * m_reducedBdrySize;
@@ -297,7 +326,11 @@ void MatrixIntraPrediction::computeReducedPred( int*const result, const int* con
 
   int sum = 0;
   for( int i = 0; i < inputSize; i++ ) { sum += input[i]; }
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+  const int offset = (1 << (MIP_SHIFT_MATRIX - 1)) - MIP_OFFSET_MATRIX * sum;
+#else
   const int offset = (1 << (shiftMatrix - 1)) - offsetMatrix * sum;
+#endif
   CHECK( inputSize != 4 * (inputSize >> 2), "Error, input size not divisible by four" );
 
   const uint8_t *weight = matrix;
@@ -321,7 +354,11 @@ void MatrixIntraPrediction::computeReducedPred( int*const result, const int* con
         tmp2 += input[i + 2] * weight[i + 2];
         tmp3 += input[i + 3] * weight[i + 3];
       }
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+      resPtr[posRes++] = ClipBD<int>(((tmp0 + tmp1 + tmp2 + tmp3 + offset) >> MIP_SHIFT_MATRIX) + inputOffset, bitDepth);
+#else
       resPtr[posRes++] = ClipBD<int>( ((tmp0 + tmp1 + tmp2 + tmp3 + offset) >> shiftMatrix) + inputOffset, bitDepth );
+#endif
 
       weight += inputSize;
     }
diff --git a/source/Lib/CommonLib/MatrixIntraPrediction.h b/source/Lib/CommonLib/MatrixIntraPrediction.h
index bf90ae11d4ea414386fe60c855787d8d8f11ae86..2452150d3f6fa46c020f2fd704e64554292cbf1c 100644
--- a/source/Lib/CommonLib/MatrixIntraPrediction.h
+++ b/source/Lib/CommonLib/MatrixIntraPrediction.h
@@ -80,11 +80,19 @@ public:
                                         const SizeType bndryStep,
                                         const unsigned int upsmpFactor );
 
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+    const uint8_t* getMatrixData(const int modeIdx) const;
+#else
     void getMatrixData(const uint8_t*& matrix, int &shiftMatrix, int &offsetMatrix, const int modeIdx) const;
+#endif
 
 
     void computeReducedPred( int*const result, const int* const input, 
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+                             const uint8_t* matrix,
+#else
                              const uint8_t*matrix, const int shiftMatrix, const int offsetMatrix,
+#endif
                              const bool transpose, const int bitDepth );
   };
 
diff --git a/source/Lib/CommonLib/MipData.h b/source/Lib/CommonLib/MipData.h
index 487565eb11e846bbc5f4e9e279f855e54f786d11..7200a9f85234c563ecd95bdb1de60e1d6d203656 100644
--- a/source/Lib/CommonLib/MipData.h
+++ b/source/Lib/CommonLib/MipData.h
@@ -35,6 +35,850 @@
 \brief    weight and bias data for matrix-based intra prediction (MIP)
 */
 
+#if JVET_Q0446_MIP_CONST_SHIFT_OFFSET
+static const uint8_t MIP_SHIFT_MATRIX  =  6;
+static const uint8_t MIP_OFFSET_MATRIX = 32;
+
+ALIGN_DATA(MEMORY_ALIGN_DEF_SIZE, const uint8_t mipMatrix4x4[16][16][4]) =
+{
+  {
+    {   32,   30,   90,   28},
+    {   32,   32,   72,   28},
+    {   34,   77,   53,   30},
+    {   51,  124,   36,   37},
+    {   31,   31,   95,   37},
+    {   33,   31,   70,   50},
+    {   52,   80,   25,   60},
+    {   78,  107,    1,   65},
+    {   31,   29,   37,   95},
+    {   38,   34,   19,  101},
+    {   73,   85,    0,   81},
+    {   92,   99,    0,   65},
+    {   34,   29,   14,  111},
+    {   48,   48,    7,  100},
+    {   80,   91,    0,   74},
+    {   89,   97,    0,   64}
+  },
+  {
+    {   31,   23,   34,   29},
+    {   31,   43,   34,   31},
+    {   30,   95,   34,   32},
+    {   29,  100,   35,   33},
+    {   31,   23,   34,   29},
+    {   31,   43,   34,   31},
+    {   30,   95,   34,   32},
+    {   29,   99,   35,   33},
+    {   31,   24,   35,   29},
+    {   31,   44,   34,   31},
+    {   30,   95,   35,   32},
+    {   29,   99,   35,   33},
+    {   31,   24,   35,   30},
+    {   31,   44,   35,   31},
+    {   30,   95,   35,   32},
+    {   29,   99,   35,   33}
+  },
+  {
+    {   32,   32,   36,   58},
+    {   32,   29,   26,   66},
+    {   36,   37,   23,   61},
+    {   79,   84,    3,   37},
+    {   32,   32,   30,   69},
+    {   33,   29,   24,   71},
+    {   44,   16,   21,   70},
+    {   96,   18,    0,   57},
+    {   32,   31,   24,   74},
+    {   33,   30,   23,   71},
+    {   36,   24,   24,   71},
+    {   59,    9,   16,   68},
+    {   32,   32,   23,   75},
+    {   33,   30,   24,   70},
+    {   32,   30,   25,   71},
+    {   36,   26,   25,   70}
+  },
+  {
+    {   32,   33,   34,   32},
+    {   32,   30,   22,   38},
+    {   29,   46,   25,   38},
+    {   53,  123,   28,   22},
+    {   32,   33,   30,   37},
+    {   32,   30,   21,   38},
+    {   32,   40,   24,   38},
+    {   64,  116,   26,   17},
+    {   32,   32,   23,   49},
+    {   32,   30,   21,   39},
+    {   34,   39,   24,   37},
+    {   72,  109,   23,   16},
+    {   33,   31,   17,   60},
+    {   32,   31,   21,   39},
+    {   35,   41,   24,   37},
+    {   72,  106,   22,   18}
+  },
+  {
+    {   34,   25,   89,   20},
+    {   38,   32,   47,   24},
+    {   40,   86,   29,   27},
+    {   38,   98,   32,   29},
+    {   34,   31,   94,   40},
+    {   44,   25,   83,   27},
+    {   54,   72,   43,   16},
+    {   47,   94,   33,   22},
+    {   33,   31,   36,   94},
+    {   43,   23,   51,   76},
+    {   62,   55,   64,   25},
+    {   57,   89,   38,   15},
+    {   32,   32,   28,  101},
+    {   38,   26,   33,   94},
+    {   55,   38,   68,   47},
+    {   59,   80,   52,   16}
+  },
+  {
+    {   28,   30,   68,   29},
+    {   23,   48,   23,   48},
+    {   39,   98,   16,   42},
+    {   84,   86,   20,   17},
+    {   25,   31,   52,   74},
+    {   38,   68,    5,   70},
+    {   95,   78,    7,   21},
+    {  127,   54,   12,    0},
+    {   30,   47,   14,  107},
+    {   79,   76,    0,   53},
+    {  127,   59,    7,    1},
+    {  127,   51,    9,    0},
+    {   50,   71,    1,   96},
+    {  109,   69,    7,   25},
+    {  127,   56,    9,    0},
+    {  123,   53,   13,    0}
+  },
+  {
+    {   40,   20,   72,   18},
+    {   48,   29,   44,   18},
+    {   53,   81,   35,   18},
+    {   48,   96,   33,   22},
+    {   45,   23,   79,   49},
+    {   61,   21,   56,   49},
+    {   72,   52,   32,   48},
+    {   65,   69,   20,   50},
+    {   41,   27,   29,   96},
+    {   49,   22,   28,   94},
+    {   52,   22,   28,   93},
+    {   49,   27,   27,   92},
+    {   37,   29,   26,   98},
+    {   39,   28,   28,   97},
+    {   38,   28,   30,   97},
+    {   38,   29,   30,   95}
+  },
+  {
+    {   33,   27,   43,   27},
+    {   32,   29,   31,   31},
+    {   31,   73,   33,   31},
+    {   35,  104,   34,   28},
+    {   32,   30,   63,   22},
+    {   33,   26,   33,   29},
+    {   33,   57,   33,   30},
+    {   37,  100,   35,   27},
+    {   32,   31,   85,   25},
+    {   34,   25,   39,   25},
+    {   35,   39,   32,   28},
+    {   40,   91,   35,   25},
+    {   32,   30,   77,   50},
+    {   34,   26,   54,   22},
+    {   37,   31,   34,   27},
+    {   45,   75,   34,   23}
+  },
+  {
+    {   34,   25,   77,   19},
+    {   36,   34,   56,   24},
+    {   41,   83,   39,   30},
+    {   47,   96,   28,   35},
+    {   34,   31,   70,   65},
+    {   38,   29,   53,   77},
+    {   43,   36,   37,   83},
+    {   48,   39,   28,   83},
+    {   33,   31,   31,   98},
+    {   33,   31,   30,   99},
+    {   34,   30,   31,   98},
+    {   36,   29,   31,   96},
+    {   32,   32,   30,   97},
+    {   32,   32,   31,   96},
+    {   31,   33,   33,   96},
+    {   32,   33,   34,   94}
+  },
+  {
+    {   30,   30,   93,   19},
+    {   31,   59,   67,   34},
+    {   31,   79,   36,   59},
+    {   30,   67,   17,   79},
+    {   30,   38,   68,   69},
+    {   29,   40,   43,   91},
+    {   26,   35,   32,  101},
+    {   23,   32,   30,  101},
+    {   26,   34,   30,  101},
+    {   23,   33,   30,  102},
+    {   20,   32,   31,  102},
+    {   18,   33,   32,  102},
+    {   23,   33,   31,  100},
+    {   20,   34,   32,  100},
+    {   18,   35,   33,  100},
+    {   18,   35,   33,  100}
+  },
+  {
+    {   31,   54,   90,   26},
+    {   32,   60,   53,   61},
+    {   34,   49,   37,   84},
+    {   34,   39,   35,   89},
+    {   35,   38,   41,   88},
+    {   35,   35,   32,   96},
+    {   35,   31,   33,   96},
+    {   35,   32,   35,   94},
+    {   34,   34,   30,   97},
+    {   35,   32,   33,   95},
+    {   35,   32,   34,   94},
+    {   35,   34,   34,   93},
+    {   34,   34,   34,   93},
+    {   35,   34,   34,   93},
+    {   35,   34,   34,   92},
+    {   36,   34,   35,   91}
+  },
+  {
+    {   32,   29,   54,   24},
+    {   31,   32,   34,   29},
+    {   31,   43,   34,   29},
+    {   32,   67,   36,   28},
+    {   31,   34,   69,   37},
+    {   31,   35,   46,   33},
+    {   30,   35,   39,   33},
+    {   30,   42,   39,   36},
+    {   31,   35,   39,   88},
+    {   30,   38,   41,   84},
+    {   30,   39,   40,   81},
+    {   39,   46,   38,   78},
+    {   31,   36,   34,   96},
+    {   34,   38,   37,   93},
+    {   55,   42,   38,   82},
+    {   89,   53,   38,   65}
+  },
+  {
+    {   32,   33,   43,   29},
+    {   32,   30,   29,   33},
+    {   31,   47,   31,   33},
+    {   33,  100,   31,   31},
+    {   32,   33,   74,   25},
+    {   32,   32,   34,   31},
+    {   32,   33,   30,   33},
+    {   32,   68,   30,   32},
+    {   32,   31,   91,   40},
+    {   32,   32,   58,   26},
+    {   31,   31,   30,   32},
+    {   31,   42,   30,   33},
+    {   32,   31,   49,   85},
+    {   32,   31,   83,   35},
+    {   31,   33,   48,   29},
+    {   31,   36,   32,   33}
+  },
+  {
+    {   31,   29,   81,   35},
+    {   32,   28,   34,   50},
+    {   31,   75,   16,   43},
+    {   34,  103,   29,   32},
+    {   32,   32,   53,   78},
+    {   31,   28,   36,   88},
+    {   30,   52,   18,   73},
+    {   52,   88,   17,   35},
+    {   32,   32,   35,   94},
+    {   30,   31,   35,   95},
+    {   36,   29,   31,   92},
+    {  100,   43,   16,   40},
+    {   32,   32,   35,   93},
+    {   30,   32,   38,   93},
+    {   55,   18,   37,   83},
+    {  127,    0,   30,   40}
+  },
+  {
+    {   31,   22,   47,   30},
+    {   31,   48,   25,   34},
+    {   30,   95,   31,   32},
+    {   32,  103,   33,   32},
+    {   30,   24,   57,   31},
+    {   30,   47,   26,   34},
+    {   31,   95,   31,   32},
+    {   43,   97,   35,   25},
+    {   29,   26,   44,   63},
+    {   37,   38,   24,   47},
+    {   74,   63,   28,   20},
+    {  110,   58,   34,    3},
+    {   46,   22,    5,  108},
+    {   93,    5,    9,   77},
+    {  127,    0,   17,   52},
+    {  127,    0,   15,   50}
+  },
+  {
+    {   32,   27,   68,   24},
+    {   35,   23,   35,   28},
+    {   35,   64,   29,   29},
+    {   37,  104,   33,   28},
+    {   32,   32,   91,   40},
+    {   36,   23,   67,   36},
+    {   49,   23,   39,   28},
+    {   60,   67,   30,   20},
+    {   32,   32,   36,   95},
+    {   35,   29,   38,   93},
+    {   50,   16,   30,   84},
+    {   72,   16,   15,   65},
+    {   32,   32,   27,  100},
+    {   33,   32,   29,  100},
+    {   37,   29,   30,   98},
+    {   48,   21,   29,   90}
+  }
+};
+
+ALIGN_DATA(MEMORY_ALIGN_DEF_SIZE, const uint8_t mipMatrix8x8[8][16][8]) =
+{
+  {
+    {   30,   63,   46,   37,   25,   33,   33,   34},
+    {   30,   60,   66,   38,   32,   31,   32,   33},
+    {   29,   45,   74,   42,   32,   32,   32,   33},
+    {   30,   39,   62,   58,   32,   33,   32,   33},
+    {   30,   66,   55,   39,   32,   30,   30,   36},
+    {   29,   54,   69,   40,   33,   31,   31,   33},
+    {   28,   48,   71,   43,   32,   33,   32,   33},
+    {   28,   41,   72,   46,   32,   34,   32,   33},
+    {   30,   66,   56,   40,   32,   33,   28,   33},
+    {   29,   55,   69,   39,   33,   33,   30,   32},
+    {   27,   46,   72,   43,   33,   33,   32,   33},
+    {   27,   42,   69,   48,   32,   34,   32,   33},
+    {   30,   63,   55,   40,   32,   33,   35,   30},
+    {   29,   56,   66,   40,   33,   33,   33,   30},
+    {   27,   47,   69,   44,   33,   33,   33,   32},
+    {   27,   42,   65,   50,   32,   34,   32,   33}
+  },
+  {
+    {   32,   33,   30,   31,   74,   30,   31,   32},
+    {   33,   56,   28,   30,   41,   29,   32,   32},
+    {   33,   77,   52,   26,   29,   34,   30,   32},
+    {   33,   37,   80,   41,   31,   34,   30,   32},
+    {   32,   32,   33,   31,   59,   76,   28,   31},
+    {   33,   31,   31,   30,   78,   40,   28,   32},
+    {   33,   47,   28,   29,   53,   27,   31,   31},
+    {   33,   61,   44,   28,   34,   32,   31,   31},
+    {   32,   31,   34,   30,   26,   64,   76,   27},
+    {   32,   31,   34,   29,   45,   86,   36,   29},
+    {   33,   27,   34,   29,   73,   55,   25,   32},
+    {   33,   33,   34,   30,   62,   33,   30,   31},
+    {   32,   31,   34,   30,   30,   29,   58,   74},
+    {   32,   31,   35,   29,   27,   53,   77,   35},
+    {   32,   30,   36,   29,   40,   80,   44,   31},
+    {   33,   28,   37,   30,   58,   60,   31,   33}
+  },
+  {
+    {   32,   51,   27,   32,   27,   50,   29,   32},
+    {   32,   95,   42,   29,   29,   42,   30,   32},
+    {   32,   27,   99,   34,   31,   41,   29,   32},
+    {   32,   34,   21,  104,   31,   42,   30,   32},
+    {   32,   45,   30,   32,    9,   88,   40,   30},
+    {   32,   77,   38,   30,    9,   76,   38,   30},
+    {   32,   38,   78,   33,   14,   67,   37,   30},
+    {   32,   30,   30,   87,   20,   59,   38,   31},
+    {   33,   37,   32,   32,   27,   18,  106,   34},
+    {   34,   44,   34,   31,   25,   17,  108,   31},
+    {   36,   39,   45,   31,   24,   15,  108,   30},
+    {   37,   31,   31,   54,   25,   14,  101,   32},
+    {   36,   33,   32,   30,   29,   37,   13,  110},
+    {   39,   32,   32,   29,   27,   37,   15,  108},
+    {   44,   33,   31,   27,   25,   37,   16,  106},
+    {   47,   30,   31,   32,   25,   34,   19,  102}
+  },
+  {
+    {   32,   48,   35,   35,   47,   68,   31,   31},
+    {   32,   33,   59,   40,   27,   71,   33,   30},
+    {   32,   29,   47,   65,   24,   62,   37,   30},
+    {   33,   33,   31,   81,   26,   50,   42,   32},
+    {   32,   30,   40,   38,   30,   70,   55,   31},
+    {   32,   20,   46,   50,   26,   55,   64,   31},
+    {   33,   30,   29,   66,   25,   41,   72,   33},
+    {   36,   34,   27,   69,   26,   31,   67,   39},
+    {   33,   28,   36,   40,   30,   26,   85,   47},
+    {   36,   27,   33,   50,   31,   20,   79,   53},
+    {   43,   30,   26,   57,   28,   17,   67,   62},
+    {   51,   27,   28,   55,   22,   23,   49,   70},
+    {   38,   29,   32,   39,   28,   30,   22,  104},
+    {   51,   31,   28,   43,   24,   31,   17,  102},
+    {   69,   23,   30,   40,   15,   38,   10,   95},
+    {   77,   13,   35,   38,    8,   43,    8,   90}
+  },
+  {
+    {   32,   38,   32,   33,  101,   40,   29,   32},
+    {   32,   40,   37,   32,  100,   36,   30,   32},
+    {   32,   37,   46,   35,   94,   33,   30,   31},
+    {   33,   34,   30,   62,   81,   35,   30,   31},
+    {   32,   32,   33,   32,   22,  102,   39,   29},
+    {   32,   31,   33,   33,   26,  104,   34,   28},
+    {   33,   33,   33,   33,   31,  103,   32,   28},
+    {   33,   32,   34,   36,   37,   94,   33,   28},
+    {   32,   33,   32,   32,   34,   24,   99,   36},
+    {   32,   34,   33,   33,   33,   30,   98,   32},
+    {   33,   33,   34,   33,   31,   37,   95,   29},
+    {   33,   33,   33,   36,   30,   46,   85,   31},
+    {   32,   33,   32,   33,   30,   34,   23,  104},
+    {   32,   34,   33,   33,   31,   32,   30,   98},
+    {   32,   33,   34,   34,   31,   29,   39,   91},
+    {   33,   33,   32,   37,   32,   30,   47,   82}
+  },
+  {
+    {   32,   52,   48,   31,   38,   76,   26,   32},
+    {   33,   19,   62,   50,   25,   50,   51,   31},
+    {   33,   30,   20,   74,   29,   29,   54,   51},
+    {   34,   35,   23,   56,   31,   25,   41,   76},
+    {   33,   25,   38,   39,   28,   39,   83,   35},
+    {   35,   28,   25,   47,   31,   23,   57,   74},
+    {   37,   35,   22,   38,   31,   27,   30,  101},
+    {   38,   32,   33,   29,   30,   31,   27,  103},
+    {   34,   32,   27,   37,   32,   25,   41,   92},
+    {   38,   33,   28,   32,   30,   31,   18,  111},
+    {   40,   32,   33,   27,   29,   33,   18,  111},
+    {   40,   32,   34,   27,   28,   33,   23,  105},
+    {   35,   32,   30,   33,   31,   33,   20,  107},
+    {   38,   31,   33,   30,   29,   33,   21,  106},
+    {   40,   32,   33,   29,   29,   34,   22,  105},
+    {   40,   32,   33,   30,   29,   34,   24,  101}
+  },
+  {
+    {   32,   28,   31,   33,   92,   33,   30,   31},
+    {   33,   30,   28,   33,   71,   26,   32,   30},
+    {   33,   60,   26,   33,   47,   28,   33,   30},
+    {   33,   63,   44,   36,   37,   31,   33,   30},
+    {   33,   30,   31,   33,   43,   90,   33,   29},
+    {   33,   28,   29,   34,   71,   71,   26,   30},
+    {   33,   30,   26,   33,   86,   45,   28,   30},
+    {   33,   38,   29,   32,   74,   32,   33,   29},
+    {   33,   32,   30,   32,   29,   41,   95,   27},
+    {   34,   31,   29,   33,   26,   71,   73,   22},
+    {   34,   31,   29,   33,   37,   88,   46,   25},
+    {   33,   32,   28,   34,   55,   75,   36,   28},
+    {   34,   31,   30,   32,   33,   27,   43,   89},
+    {   35,   32,   28,   33,   33,   23,   77,   59},
+    {   34,   33,   28,   33,   30,   35,   91,   37},
+    {   34,   34,   28,   34,   33,   53,   74,   31}
+  },
+  {
+    {   33,   49,   26,   32,   26,   52,   28,   31},
+    {   33,   71,   72,   24,   30,   32,   34,   31},
+    {   32,   23,   70,   68,   32,   32,   32,   32},
+    {   31,   33,   21,  106,   33,   32,   32,   33},
+    {   34,   47,   32,   29,    5,   86,   44,   26},
+    {   34,   44,   89,   28,   28,   37,   33,   30},
+    {   32,   27,   46,   89,   33,   31,   31,   32},
+    {   30,   33,   20,  107,   33,   33,   32,   33},
+    {   35,   39,   42,   27,   26,   24,   92,   35},
+    {   34,   27,   87,   43,   30,   34,   38,   31},
+    {   31,   31,   32,  100,   32,   33,   30,   32},
+    {   29,   32,   22,  106,   33,   33,   32,   33},
+    {   35,   29,   47,   32,   32,   32,   17,  100},
+    {   34,   24,   69,   60,   34,   33,   28,   44},
+    {   31,   33,   31,   99,   32,   33,   32,   31},
+    {   29,   33,   25,  103,   33,   33,   32,   35}
+  }
+};
+
+ALIGN_DATA(MEMORY_ALIGN_DEF_SIZE, const uint8_t mipMatrix16x16[6][64][7]) =
+{
+  {
+    {   42,   37,   33,   27,   44,   33,   35},
+    {   71,   39,   34,   24,   36,   35,   36},
+    {   77,   46,   35,   33,   30,   34,   36},
+    {   64,   60,   35,   33,   31,   32,   36},
+    {   49,   71,   38,   32,   32,   31,   36},
+    {   42,   66,   50,   33,   31,   32,   36},
+    {   40,   52,   67,   33,   31,   32,   35},
+    {   38,   43,   75,   33,   32,   32,   35},
+    {   56,   40,   33,   26,   43,   38,   36},
+    {   70,   49,   34,   30,   28,   38,   38},
+    {   65,   57,   36,   34,   28,   33,   39},
+    {   59,   60,   39,   33,   30,   31,   38},
+    {   55,   60,   43,   33,   30,   31,   38},
+    {   51,   61,   47,   33,   30,   32,   37},
+    {   46,   62,   51,   34,   30,   32,   37},
+    {   42,   60,   55,   33,   31,   32,   37},
+    {   60,   42,   34,   30,   37,   43,   38},
+    {   68,   52,   35,   35,   22,   37,   40},
+    {   62,   58,   37,   34,   28,   31,   40},
+    {   58,   59,   41,   33,   30,   30,   39},
+    {   56,   59,   44,   34,   30,   31,   38},
+    {   53,   60,   45,   33,   30,   31,   38},
+    {   49,   65,   45,   33,   30,   31,   38},
+    {   45,   64,   47,   33,   31,   32,   38},
+    {   59,   44,   35,   31,   34,   43,   41},
+    {   66,   53,   36,   35,   25,   31,   43},
+    {   61,   58,   38,   34,   29,   30,   40},
+    {   59,   57,   41,   33,   30,   31,   39},
+    {   57,   58,   43,   33,   30,   31,   39},
+    {   54,   61,   43,   33,   31,   31,   39},
+    {   51,   64,   43,   33,   31,   31,   39},
+    {   48,   64,   45,   33,   32,   31,   39},
+    {   57,   45,   35,   30,   35,   40,   44},
+    {   65,   54,   37,   33,   33,   24,   44},
+    {   63,   56,   38,   34,   30,   29,   39},
+    {   61,   56,   41,   34,   30,   32,   39},
+    {   58,   58,   42,   33,   31,   31,   39},
+    {   54,   62,   41,   33,   31,   31,   39},
+    {   51,   65,   42,   33,   31,   31,   39},
+    {   48,   63,   43,   33,   32,   31,   39},
+    {   55,   46,   35,   30,   36,   38,   47},
+    {   65,   53,   37,   32,   36,   26,   40},
+    {   65,   54,   38,   33,   31,   30,   38},
+    {   63,   55,   39,   33,   30,   32,   38},
+    {   59,   58,   40,   33,   31,   31,   39},
+    {   54,   64,   40,   33,   31,   30,   40},
+    {   49,   66,   40,   32,   32,   30,   41},
+    {   48,   64,   42,   32,   32,   30,   41},
+    {   54,   46,   35,   30,   34,   39,   49},
+    {   64,   52,   36,   32,   34,   34,   35},
+    {   65,   53,   37,   33,   32,   32,   37},
+    {   63,   55,   38,   33,   31,   31,   39},
+    {   59,   60,   38,   33,   31,   31,   40},
+    {   54,   64,   38,   33,   32,   30,   40},
+    {   49,   66,   39,   33,   32,   29,   41},
+    {   47,   64,   42,   32,   33,   29,   42},
+    {   51,   46,   35,   31,   33,   37,   54},
+    {   61,   51,   36,   32,   33,   38,   36},
+    {   63,   53,   37,   32,   32,   34,   37},
+    {   62,   55,   37,   33,   32,   32,   39},
+    {   58,   59,   37,   33,   32,   31,   40},
+    {   53,   63,   38,   33,   32,   31,   40},
+    {   49,   64,   40,   33,   33,   30,   41},
+    {   46,   62,   42,   33,   33,   30,   42}
+  },
+  {
+    {   39,   34,   33,   58,   44,   31,   32},
+    {   60,   38,   32,   40,   51,   30,   31},
+    {   73,   49,   31,   39,   48,   32,   31},
+    {   60,   73,   30,   39,   46,   33,   32},
+    {   43,   87,   35,   38,   45,   33,   32},
+    {   35,   78,   54,   36,   45,   33,   32},
+    {   33,   47,   86,   35,   44,   33,   32},
+    {   31,   17,  114,   34,   44,   34,   33},
+    {   43,   37,   32,   53,   70,   30,   31},
+    {   53,   50,   30,   42,   72,   31,   30},
+    {   52,   66,   30,   39,   70,   32,   30},
+    {   46,   78,   35,   37,   68,   34,   30},
+    {   43,   75,   48,   37,   66,   34,   30},
+    {   40,   62,   68,   35,   65,   35,   30},
+    {   33,   37,   97,   33,   62,   37,   31},
+    {   26,   14,  122,   32,   59,   38,   33},
+    {   40,   39,   33,   34,   87,   37,   30},
+    {   45,   54,   32,   34,   84,   41,   29},
+    {   41,   70,   35,   33,   83,   40,   29},
+    {   37,   73,   44,   32,   82,   40,   30},
+    {   37,   65,   60,   31,   81,   41,   29},
+    {   35,   48,   82,   30,   79,   43,   29},
+    {   28,   27,  108,   28,   76,   45,   30},
+    {   19,   11,  127,   27,   70,   46,   32},
+    {   38,   40,   34,   27,   73,   62,   28},
+    {   39,   54,   35,   30,   73,   62,   28},
+    {   33,   65,   41,   29,   75,   59,   28},
+    {   30,   65,   53,   27,   76,   58,   29},
+    {   29,   53,   72,   26,   77,   58,   29},
+    {   27,   35,   95,   24,   77,   60,   28},
+    {   19,   19,  117,   23,   74,   61,   30},
+    {    9,   16,  127,   23,   68,   60,   34},
+    {   35,   40,   35,   29,   44,   89,   30},
+    {   33,   51,   39,   29,   49,   86,   30},
+    {   28,   57,   49,   28,   53,   83,   30},
+    {   24,   52,   65,   26,   56,   82,   30},
+    {   22,   39,   86,   24,   58,   82,   30},
+    {   18,   22,  108,   23,   59,   82,   31},
+    {   10,   13,  125,   22,   58,   80,   33},
+    {    0,   19,  127,   22,   56,   74,   40},
+    {   33,   40,   36,   31,   28,   90,   45},
+    {   29,   46,   44,   29,   31,   92,   43},
+    {   24,   45,   58,   28,   34,   91,   43},
+    {   19,   37,   78,   26,   37,   91,   43},
+    {   15,   22,   99,   25,   38,   91,   42},
+    {   11,   11,  118,   24,   39,   90,   44},
+    {    2,   11,  127,   23,   41,   85,   48},
+    {    0,   17,  127,   23,   43,   75,   55},
+    {   31,   37,   39,   30,   28,   54,   82},
+    {   27,   37,   52,   28,   30,   58,   79},
+    {   22,   30,   70,   27,   32,   58,   79},
+    {   15,   19,   91,   26,   33,   58,   79},
+    {   10,    8,  111,   25,   34,   58,   79},
+    {    5,    2,  125,   25,   35,   57,   80},
+    {    0,    9,  127,   25,   36,   53,   84},
+    {    0,   13,  127,   25,   39,   47,   88},
+    {   28,   29,   46,   28,   39,    2,  123},
+    {   24,   24,   62,   27,   41,    1,  125},
+    {   19,   14,   81,   25,   43,    0,  126},
+    {   13,    4,  101,   24,   44,    0,  127},
+    {    6,    0,  116,   23,   45,    0,  127},
+    {    0,    0,  126,   23,   45,    1,  127},
+    {    0,    4,  127,   25,   44,    2,  127},
+    {    0,    9,  127,   25,   44,    3,  127}
+  },
+  {
+    {   30,   32,   32,   42,   34,   32,   32},
+    {   63,   26,   34,   16,   38,   32,   32},
+    {   98,   26,   34,   25,   34,   33,   32},
+    {   75,   61,   30,   31,   32,   33,   32},
+    {   36,   94,   32,   30,   33,   32,   32},
+    {   26,   76,   58,   30,   33,   32,   32},
+    {   30,   39,   91,   31,   32,   33,   31},
+    {   32,   23,  105,   32,   32,   32,   32},
+    {   34,   30,   33,   31,   52,   29,   32},
+    {   66,   24,   34,   11,   41,   33,   32},
+    {   97,   28,   34,   24,   34,   33,   32},
+    {   71,   65,   30,   30,   32,   33,   32},
+    {   34,   92,   35,   30,   33,   32,   32},
+    {   26,   70,   64,   29,   34,   32,   32},
+    {   30,   37,   94,   30,   33,   32,   31},
+    {   32,   23,  105,   31,   33,   33,   31},
+    {   37,   29,   33,    8,   79,   27,   32},
+    {   71,   22,   35,    5,   50,   32,   32},
+    {   98,   29,   34,   23,   34,   34,   32},
+    {   66,   70,   30,   31,   31,   33,   32},
+    {   31,   92,   38,   30,   33,   32,   32},
+    {   26,   66,   68,   29,   34,   32,   31},
+    {   30,   34,   97,   30,   34,   33,   31},
+    {   31,   22,  106,   30,   34,   33,   31},
+    {   40,   28,   34,    0,   76,   46,   28},
+    {   76,   21,   35,    0,   55,   35,   32},
+    {   97,   32,   34,   21,   37,   33,   33},
+    {   61,   75,   29,   30,   32,   32,   32},
+    {   29,   92,   40,   29,   33,   32,   32},
+    {   26,   62,   73,   29,   34,   32,   31},
+    {   29,   32,   99,   30,   34,   33,   30},
+    {   31,   22,  107,   30,   34,   33,   31},
+    {   42,   27,   34,    1,   48,   79,   25},
+    {   80,   20,   35,    0,   48,   47,   31},
+    {   94,   36,   32,   17,   40,   33,   33},
+    {   55,   80,   29,   27,   35,   31,   32},
+    {   27,   90,   43,   28,   34,   32,   31},
+    {   26,   58,   76,   29,   33,   33,   30},
+    {   29,   30,  101,   29,   34,   34,   30},
+    {   31,   21,  108,   29,   35,   34,   30},
+    {   44,   26,   34,    6,   30,   80,   40},
+    {   81,   21,   35,    0,   41,   52,   35},
+    {   90,   41,   31,   14,   41,   35,   33},
+    {   51,   82,   29,   24,   37,   32,   32},
+    {   27,   87,   47,   27,   35,   32,   31},
+    {   26,   54,   79,   29,   34,   33,   30},
+    {   29,   29,  102,   28,   34,   33,   30},
+    {   31,   21,  108,   28,   35,   33,   31},
+    {   47,   26,   34,    7,   34,   44,   75},
+    {   80,   24,   34,    0,   41,   41,   50},
+    {   84,   45,   31,   12,   40,   36,   36},
+    {   49,   81,   31,   22,   37,   33,   32},
+    {   28,   81,   51,   26,   35,   33,   31},
+    {   28,   51,   81,   28,   34,   33,   30},
+    {   29,   30,  101,   28,   35,   33,   31},
+    {   31,   22,  107,   28,   35,   33,   32},
+    {   48,   27,   34,   10,   40,   16,   97},
+    {   75,   27,   34,    3,   42,   26,   66},
+    {   77,   47,   33,   12,   40,   32,   43},
+    {   49,   75,   36,   21,   37,   33,   35},
+    {   32,   72,   55,   25,   36,   33,   32},
+    {   30,   49,   81,   27,   35,   33,   31},
+    {   30,   32,   98,   28,   35,   32,   32},
+    {   31,   24,  104,   28,   35,   32,   33}
+  },
+  {
+    {   36,   29,   33,   43,   47,   29,   31},
+    {   74,   20,   35,   19,   47,   34,   32},
+    {   92,   35,   32,   29,   31,   40,   34},
+    {   53,   80,   26,   33,   28,   36,   37},
+    {   24,   91,   41,   31,   31,   31,   38},
+    {   25,   57,   74,   31,   32,   30,   37},
+    {   32,   28,   99,   32,   32,   29,   36},
+    {   34,   20,  105,   33,   32,   30,   35},
+    {   50,   26,   34,   33,   74,   30,   31},
+    {   75,   28,   33,   23,   46,   47,   33},
+    {   64,   58,   29,   30,   26,   46,   40},
+    {   31,   85,   37,   31,   27,   33,   44},
+    {   22,   67,   64,   30,   31,   28,   42},
+    {   29,   35,   93,   31,   32,   27,   40},
+    {   33,   20,  105,   32,   33,   27,   37},
+    {   34,   19,  106,   33,   32,   29,   36},
+    {   51,   29,   33,   25,   72,   51,   30},
+    {   61,   42,   31,   30,   31,   60,   39},
+    {   40,   70,   34,   32,   24,   41,   50},
+    {   22,   72,   54,   30,   31,   27,   50},
+    {   25,   44,   83,   30,   33,   25,   44},
+    {   32,   23,  102,   32,   33,   26,   40},
+    {   34,   18,  107,   32,   33,   28,   37},
+    {   34,   19,  105,   33,   32,   30,   35},
+    {   45,   35,   32,   30,   39,   79,   33},
+    {   43,   53,   33,   35,   24,   53,   55},
+    {   27,   67,   45,   32,   29,   27,   61},
+    {   22,   53,   72,   30,   33,   22,   52},
+    {   28,   31,   95,   31,   33,   25,   43},
+    {   32,   20,  105,   32,   33,   27,   38},
+    {   34,   18,  107,   32,   32,   29,   36},
+    {   34,   20,  105,   33,   31,   31,   35},
+    {   38,   40,   32,   35,   23,   72,   54},
+    {   31,   55,   39,   34,   29,   32,   73},
+    {   22,   57,   60,   31,   35,   18,   64},
+    {   25,   39,   86,   31,   35,   22,   49},
+    {   30,   24,  101,   32,   33,   27,   40},
+    {   33,   19,  106,   32,   32,   30,   36},
+    {   34,   18,  107,   33,   31,   31,   35},
+    {   34,   20,  104,   33,   31,   32,   34},
+    {   33,   42,   35,   34,   28,   39,   82},
+    {   26,   51,   50,   33,   34,   18,   80},
+    {   23,   46,   74,   31,   35,   20,   59},
+    {   27,   32,   93,   32,   34,   26,   44},
+    {   31,   22,  103,   32,   32,   30,   37},
+    {   33,   19,  106,   33,   31,   31,   35},
+    {   34,   19,  106,   33,   31,   32,   34},
+    {   35,   21,  103,   34,   31,   32,   34},
+    {   29,   41,   41,   33,   34,   20,   92},
+    {   24,   44,   62,   34,   35,   18,   73},
+    {   24,   37,   83,   34,   33,   25,   52},
+    {   28,   28,   97,   33,   32,   30,   40},
+    {   32,   23,  103,   33,   31,   32,   36},
+    {   34,   20,  105,   34,   30,   33,   34},
+    {   35,   20,  104,   34,   30,   33,   33},
+    {   35,   22,  102,   34,   30,   33,   34},
+    {   27,   38,   51,   34,   34,   20,   86},
+    {   26,   37,   71,   35,   34,   24,   64},
+    {   27,   33,   87,   35,   32,   30,   47},
+    {   30,   28,   96,   34,   31,   32,   39},
+    {   32,   24,  100,   35,   30,   32,   36},
+    {   34,   23,  101,   34,   30,   33,   34},
+    {   35,   23,  101,   34,   30,   32,   34},
+    {   34,   24,   99,   35,   30,   33,   34}
+  },
+  {
+    {   39,   30,   31,   67,   33,   34,   31},
+    {   72,   21,   32,   43,   39,   33,   31},
+    {  100,   23,   32,   35,   39,   34,   31},
+    {   75,   63,   24,   32,   38,   34,   32},
+    {   32,   98,   26,   29,   37,   35,   32},
+    {   22,   77,   55,   29,   36,   35,   31},
+    {   31,   37,   90,   31,   35,   35,   32},
+    {   35,   22,  100,   33,   33,   36,   33},
+    {   47,   29,   32,   74,   54,   32,   31},
+    {   71,   24,   32,   60,   50,   36,   30},
+    {   86,   31,   30,   46,   48,   37,   30},
+    {   65,   63,   25,   34,   46,   39,   30},
+    {   33,   85,   32,   28,   43,   40,   30},
+    {   26,   64,   60,   27,   39,   41,   30},
+    {   33,   33,   87,   29,   35,   41,   31},
+    {   37,   23,   93,   32,   33,   41,   32},
+    {   41,   32,   32,   45,   84,   32,   32},
+    {   55,   31,   32,   50,   70,   40,   30},
+    {   62,   37,   31,   45,   61,   45,   29},
+    {   53,   55,   31,   36,   55,   48,   29},
+    {   38,   63,   40,   29,   48,   50,   28},
+    {   34,   49,   60,   27,   43,   51,   29},
+    {   38,   30,   78,   28,   38,   50,   31},
+    {   40,   24,   83,   30,   36,   48,   33},
+    {   35,   33,   33,   29,   75,   58,   29},
+    {   39,   35,   33,   34,   68,   59,   29},
+    {   41,   39,   34,   36,   61,   62,   29},
+    {   41,   43,   37,   33,   54,   64,   28},
+    {   41,   43,   45,   30,   48,   65,   29},
+    {   42,   36,   56,   27,   44,   63,   30},
+    {   42,   30,   65,   27,   41,   60,   33},
+    {   42,   28,   68,   28,   37,   56,   36},
+    {   33,   34,   33,   31,   42,   88,   30},
+    {   31,   36,   34,   31,   44,   84,   31},
+    {   31,   37,   35,   32,   43,   83,   31},
+    {   35,   35,   39,   32,   40,   82,   31},
+    {   40,   32,   44,   31,   38,   81,   31},
+    {   44,   30,   48,   30,   37,   78,   33},
+    {   44,   30,   52,   28,   37,   72,   36},
+    {   43,   30,   55,   29,   35,   66,   40},
+    {   32,   33,   33,   34,   25,   85,   48},
+    {   30,   34,   34,   33,   25,   88,   44},
+    {   30,   34,   36,   34,   25,   90,   41},
+    {   33,   32,   38,   34,   25,   90,   40},
+    {   38,   29,   41,   34,   26,   88,   40},
+    {   42,   29,   41,   33,   27,   85,   41},
+    {   43,   30,   42,   31,   28,   80,   43},
+    {   42,   31,   45,   31,   30,   72,   47},
+    {   32,   33,   33,   33,   26,   54,   79},
+    {   31,   32,   34,   35,   20,   68,   68},
+    {   32,   32,   35,   36,   17,   76,   62},
+    {   34,   31,   36,   36,   17,   79,   59},
+    {   37,   29,   37,   36,   18,   78,   58},
+    {   39,   29,   37,   35,   20,   77,   58},
+    {   41,   30,   37,   34,   22,   74,   58},
+    {   40,   31,   40,   32,   26,   68,   59},
+    {   33,   31,   34,   33,   29,   31,   98},
+    {   34,   30,   34,   35,   23,   45,   88},
+    {   34,   31,   34,   36,   20,   54,   82},
+    {   35,   31,   34,   36,   18,   59,   78},
+    {   36,   31,   34,   37,   19,   60,   76},
+    {   38,   30,   34,   36,   20,   61,   74},
+    {   39,   31,   35,   35,   22,   60,   73},
+    {   39,   31,   37,   34,   24,   59,   71}
+  },
+  {
+    {   30,   33,   32,   55,   32,   32,   32},
+    {   47,   30,   31,   29,   36,   32,   32},
+    {   81,   28,   32,   28,   34,   32,   32},
+    {   85,   46,   29,   32,   32,   33,   32},
+    {   54,   82,   26,   32,   32,   33,   32},
+    {   30,   90,   38,   31,   32,   33,   32},
+    {   30,   56,   73,   31,   33,   32,   32},
+    {   37,   21,  102,   32,   32,   32,   32},
+    {   33,   32,   31,   68,   39,   31,   31},
+    {   38,   32,   31,   43,   34,   33,   31},
+    {   63,   30,   31,   29,   34,   32,   32},
+    {   82,   37,   30,   29,   33,   32,   32},
+    {   71,   63,   27,   31,   32,   33,   32},
+    {   44,   86,   30,   30,   33,   33,   32},
+    {   33,   72,   55,   30,   32,   32,   31},
+    {   37,   37,   86,   31,   32,   33,   31},
+    {   34,   33,   32,   60,   61,   29,   32},
+    {   36,   33,   31,   56,   38,   32,   31},
+    {   51,   30,   31,   38,   33,   33,   32},
+    {   75,   31,   31,   30,   33,   33,   32},
+    {   80,   47,   29,   30,   32,   33,   31},
+    {   60,   73,   27,   30,   33,   33,   31},
+    {   41,   78,   41,   30,   33,   32,   31},
+    {   38,   53,   68,   30,   32,   33,   31},
+    {   33,   33,   32,   43,   77,   35,   30},
+    {   35,   33,   31,   55,   54,   29,   32},
+    {   43,   32,   31,   46,   39,   31,   32},
+    {   64,   30,   31,   35,   34,   33,   32},
+    {   79,   37,   30,   31,   32,   33,   31},
+    {   73,   57,   28,   30,   32,   33,   31},
+    {   54,   73,   33,   30,   32,   33,   31},
+    {   43,   64,   52,   30,   32,   33,   31},
+    {   33,   33,   32,   34,   68,   58,   28},
+    {   34,   33,   31,   45,   70,   33,   31},
+    {   38,   33,   31,   48,   52,   29,   32},
+    {   54,   31,   31,   40,   39,   31,   32},
+    {   73,   32,   31,   34,   34,   33,   31},
+    {   77,   45,   29,   31,   32,   32,   32},
+    {   65,   63,   30,   31,   31,   33,   31},
+    {   51,   66,   42,   30,   32,   33,   31},
+    {   33,   32,   32,   34,   44,   81,   31},
+    {   34,   33,   31,   38,   66,   52,   28},
+    {   36,   33,   30,   44,   62,   34,   31},
+    {   47,   31,   31,   43,   48,   30,   32},
+    {   64,   31,   31,   38,   38,   32,   32},
+    {   75,   38,   30,   33,   34,   32,   32},
+    {   71,   53,   30,   31,   32,   33,   32},
+    {   59,   61,   37,   30,   32,   33,   32},
+    {   33,   32,   31,   35,   31,   71,   54},
+    {   34,   33,   31,   37,   49,   70,   33},
+    {   36,   33,   31,   41,   60,   48,   30},
+    {   43,   32,   31,   43,   54,   35,   31},
+    {   56,   31,   31,   40,   44,   32,   32},
+    {   68,   35,   30,   36,   37,   32,   32},
+    {   70,   45,   30,   33,   34,   33,   32},
+    {   63,   55,   35,   31,   33,   33,   32},
+    {   33,   32,   31,   33,   34,   36,   87},
+    {   34,   32,   31,   36,   38,   62,   52},
+    {   36,   33,   31,   39,   50,   57,   36},
+    {   41,   33,   31,   41,   53,   43,   33},
+    {   50,   33,   31,   41,   48,   36,   32},
+    {   59,   35,   31,   37,   41,   34,   32},
+    {   65,   42,   31,   35,   36,   33,   32},
+    {   62,   49,   35,   33,   34,   34,   33}
+  }
+};
+#else
 ALIGN_DATA(MEMORY_ALIGN_DEF_SIZE, const uint8_t mipMatrix4x4[16][16][4]) =
 {
   {
@@ -892,3 +1736,4 @@ ALIGN_DATA(MEMORY_ALIGN_DEF_SIZE, const uint8_t mipOffsetMatrix16x16[6]) =
 
 ALIGN_DATA(MEMORY_ALIGN_DEF_SIZE, const uint8_t mipShiftMatrix16x16[6]) =
 {    6,    7,    5,    6,    6,    6};
+#endif
\ No newline at end of file
diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp
index 7c0960cb71eade8f2df88a1b26038d034d460c63..5a68bee8aee8913ad2830b7874efbbb97c8db157 100644
--- a/source/Lib/CommonLib/RdCost.cpp
+++ b/source/Lib/CommonLib/RdCost.cpp
@@ -205,6 +205,10 @@ void RdCost::init()
 
   m_afpDistortFunc[DF_SAD_INTERMEDIATE_BITDEPTH] = RdCost::xGetSAD;
 
+#if JVET_Q0806
+  m_afpDistortFunc[DF_SAD_WITH_MASK] = RdCost::xGetSADwMask;
+#endif
+
 #if ENABLE_SIMD_OPT_DIST
 #ifdef TARGET_SIMD_X86
   initRdCostX86();
@@ -318,6 +322,15 @@ void RdCost::setDistParam( DistParam &rcDP, const CPelBuf &org, const Pel* piRef
       rcDP.subShift = 1;
     }
   }
+#if JVET_Q0806
+  else if( subShiftMode == 3 )
+  {
+    if (rcDP.org.height > 8 )
+    {
+      rcDP.subShift = 1;
+    }
+  }
+#endif
 }
 
 void RdCost::setDistParam( DistParam &rcDP, const CPelBuf &org, const CPelBuf &cur, int bitDepth, ComponentID compID, bool useHadamard )
@@ -3452,4 +3465,69 @@ Distortion RdCost::xGetMRHADs( const DistParam &rcDtParam )
 
   return m_afpDistortFunc[DF_HAD]( modDistParam );
 }
+
+#if JVET_Q0806
+void RdCost::setDistParam( DistParam &rcDP, const CPelBuf &org, const Pel* piRefY, int iRefStride, const Pel* mask, int iMaskStride, int stepX, int iMaskStride2, int bitDepth, ComponentID compID)
+{
+  rcDP.bitDepth     = bitDepth;
+  rcDP.compID       = compID;
+
+  // set Original & Curr Pointer / Stride
+  rcDP.org          = org;
+  rcDP.cur.buf      = piRefY;
+  rcDP.cur.stride   = iRefStride;
+
+  // set Mask
+  rcDP.mask         = mask;
+  rcDP.maskStride   = iMaskStride;
+  rcDP.stepX = stepX;
+  rcDP.maskStride2 = iMaskStride2;
+
+  // set Block Width / Height
+  rcDP.cur.width    = org.width;
+  rcDP.cur.height   = org.height;
+  rcDP.maximumDistortionForEarlyExit = std::numeric_limits<Distortion>::max();
+
+  // set Cost function for motion estimation with Mask
+  rcDP.distFunc = m_afpDistortFunc[ DF_SAD_WITH_MASK ];
+}
+
+Distortion RdCost::xGetSADwMask( const DistParam& rcDtParam )
+{
+  if ( rcDtParam.applyWeight )
+  {
+    return RdCostWeightPrediction::xGetSADw( rcDtParam );
+  }
+
+  const Pel* org           = rcDtParam.org.buf;
+  const Pel* cur           = rcDtParam.cur.buf;
+  const Pel* mask          = rcDtParam.mask;
+  const int  cols           = rcDtParam.org.width;
+  int        rows           = rcDtParam.org.height;
+  const int  subShift       = rcDtParam.subShift;
+  const int  subStep        = ( 1 << subShift);
+  const int  strideCur      = rcDtParam.cur.stride * subStep;
+  const int  strideOrg      = rcDtParam.org.stride * subStep;
+  const int  strideMask     = rcDtParam.maskStride * subStep;
+  const int  stepX = rcDtParam.stepX;
+  const int  strideMask2 = rcDtParam.maskStride2;
+  const uint32_t distortionShift = DISTORTION_PRECISION_ADJUSTMENT(rcDtParam.bitDepth);
+
+  Distortion sum = 0;
+  for (; rows != 0; rows -= subStep)
+  {
+    for (int n = 0; n < cols; n++)
+    {
+      sum += abs(org[n] - cur[n]) * *mask;
+      mask += stepX;
+    }
+    org += strideOrg;
+    cur += strideCur;
+    mask += strideMask;
+    mask += strideMask2;
+  }
+  sum <<= subShift;
+  return (sum >> distortionShift );
+}
+#endif
 //! \}
diff --git a/source/Lib/CommonLib/RdCost.h b/source/Lib/CommonLib/RdCost.h
index a7aef6fa7700fbe9cac8236d0317687c167ff53a..7d10e131abeee507b6dd52fb589a2d843f2c060b 100644
--- a/source/Lib/CommonLib/RdCost.h
+++ b/source/Lib/CommonLib/RdCost.h
@@ -71,6 +71,12 @@ public:
   CPelBuf               cur;
 #if WCG_EXT
   CPelBuf               orgLuma;
+#endif
+#if JVET_Q0806
+  const Pel*            mask;
+  int                   maskStride;
+  int                   stepX;
+  int                   maskStride2;
 #endif
   int                   step;
   FpDistFunc            distFunc;
@@ -90,7 +96,14 @@ public:
   int                   cShiftX;
   int                   cShiftY;
   DistParam() :
-  org(), cur(), step( 1 ), bitDepth( 0 ), useMR( false ), applyWeight( false ), isBiPred( false ), wpCur( nullptr ), compID( MAX_NUM_COMPONENT ), maximumDistortionForEarlyExit( std::numeric_limits<Distortion>::max() ), subShift( 0 )
+  org(), cur(), 
+#if JVET_Q0806
+  mask( nullptr ),
+  maskStride( 0 ),
+  stepX(0),
+  maskStride2(0),
+#endif
+  step( 1 ), bitDepth( 0 ), useMR( false ), applyWeight( false ), isBiPred( false ), wpCur( nullptr ), compID( MAX_NUM_COMPONENT ), maximumDistortionForEarlyExit( std::numeric_limits<Distortion>::max() ), subShift( 0 )
   , cShiftX(-1), cShiftY(-1)
   { }
 };
@@ -167,6 +180,9 @@ public:
   void           setDistParam( DistParam &rcDP, const CPelBuf &org, const Pel* piRefY , int iRefStride, int bitDepth, ComponentID compID, int subShiftMode = 0, int step = 1, bool useHadamard = false );
   void           setDistParam( DistParam &rcDP, const CPelBuf &org, const CPelBuf &cur, int bitDepth, ComponentID compID, bool useHadamard = false );
   void           setDistParam( DistParam &rcDP, const Pel* pOrg, const Pel* piRefY, int iOrgStride, int iRefStride, int bitDepth, ComponentID compID, int width, int height, int subShiftMode = 0, int step = 1, bool useHadamard = false, bool bioApplied = false );
+#if JVET_Q0806
+  void           setDistParam( DistParam &rcDP, const CPelBuf &org, const Pel* piRefY, int iRefStride, const Pel* mask, int iMaskStride, int stepX, int iMaskStride2, int bitDepth,  ComponentID compID);
+#endif
 
   double         getMotionLambda          ( )  { return m_dLambdaMotionSAD; }
   void           selectMotionLambda       ( )  { m_motionLambda = getMotionLambda( ); }
@@ -351,6 +367,9 @@ private:
   static Distortion xGetSAD48         ( const DistParam& pcDtParam );
 
   static Distortion xGetSAD_full      ( const DistParam& pcDtParam );
+#if JVET_Q0806
+  static Distortion xGetSADwMask      ( const DistParam& pcDtParam );
+#endif
 
   static Distortion xGetMRSAD         ( const DistParam& pcDtParam );
   static Distortion xGetMRSAD4        ( const DistParam& pcDtParam );
@@ -389,6 +408,11 @@ private:
 
   template<X86_VEXT vext>
   static Distortion xGetHADs_SIMD   ( const DistParam& pcDtParam );
+
+#if JVET_Q0806
+  template< X86_VEXT vext >
+  static Distortion xGetSADwMask_SIMD( const DistParam& pcDtParam );
+#endif
 #endif
 
 public:
@@ -399,6 +423,9 @@ public:
   Distortion   getDistPart( const CPelBuf &org, const CPelBuf &cur, int bitDepth, const ComponentID compID, DFunc eDFunc );
 #endif
 
+#if JVET_Q0806
+  Distortion   getDistPart(const CPelBuf &org, const CPelBuf &cur, const Pel* mask, int bitDepth, const ComponentID compID, DFunc eDFunc);
+#endif
 };// END CLASS DEFINITION RdCost
 
 //! \}
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index 5bc2f227a26e924598f0185c9169e8450619e685..7bd1333159a6690ae84778fda2ff9d2832488fe0 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -403,6 +403,7 @@ void initROM()
     }
   }
 
+#if !JVET_Q0806
   for( int idxH = MAX_CU_DEPTH - MIN_CU_LOG2; idxH >= 0; --idxH )
   {
     for( int idxW = MAX_CU_DEPTH - MIN_CU_LOG2; idxW >= 0; --idxW )
@@ -446,8 +447,23 @@ void initROM()
       }
     }
   }
+#else
+  initGeoTemplate();
+#endif
 
   ::memset(g_isReusedUniMVsFilled, 0, sizeof(g_isReusedUniMVsFilled));
+
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  for (int qp = 0; qp < 57; qp++)
+  {
+    int qpRem = (qp + 12) % 6;
+    int qpPer = (qp + 12) / 6;
+    int quantiserScale = g_quantScales[0][qpRem];
+    int quantiserRightShift = QUANT_SHIFT + qpPer;
+    double threshQP = ((double)(1 << quantiserRightShift)) / quantiserScale;
+    g_paletteQuant[qp] = (int)(threshQP*0.16 + 0.5);
+  }
+#endif
 }
 
 void destroyROM()
@@ -473,6 +489,7 @@ void destroyROM()
   delete gp_sizeIdxInfo;
   gp_sizeIdxInfo = nullptr;
 
+#if !JVET_Q0806
   for (int idxH = 0; idxH < MAX_CU_DEPTH - MIN_CU_LOG2 + 2; ++idxH)
   {
     for (int idxW = 0; idxW < MAX_CU_DEPTH - MIN_CU_LOG2 + 2; ++idxW)
@@ -483,6 +500,21 @@ void destroyROM()
       g_triangleWeights[1][idxH][idxW] = nullptr;
     }
   }
+#else
+  for( int modeIdx = 0; modeIdx < GEO_NUM_PARTITION_MODE; modeIdx++ )
+  {
+    delete[] g_GeoParams[modeIdx];
+    g_GeoParams[modeIdx] = nullptr;
+  }
+  delete[] g_GeoParams;
+  for( int i = 0; i < GEO_NUM_PRESTORED_MASK; i++ )
+  {
+    delete[] g_globalGeoWeights   [i];
+    delete[] g_globalGeoEncSADmask[i];
+    g_globalGeoWeights   [i] = nullptr;
+    g_globalGeoEncSADmask[i] = nullptr;
+  }
+#endif
 }
 
 // ====================================================================================================================
@@ -708,12 +740,102 @@ const uint32_t g_scalingListSize [SCALING_LIST_SIZE_NUM] = { 1, 4, 16, 64, 256,
 const uint32_t g_scalingListSizeX[SCALING_LIST_SIZE_NUM] = { 1, 2,  4,  8,  16,   32,   64,   128 };
 
 
+#if !JVET_Q0806
 uint8_t g_triangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2];
 int16_t *g_triangleWeights[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 2][MAX_CU_DEPTH - MIN_CU_LOG2 + 2];
+#endif
+
 Mv   g_reusedUniMVs[32][32][8][8][2][33];
 bool g_isReusedUniMVsFilled[32][32][8][8];
 
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+uint16_t g_paletteQuant[57];
+#else
 const uint8_t g_paletteQuant[52] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 24, 23, 25, 26, 28, 29, 31, 32, 34, 36, 37, 39, 41, 42, 45 };
+#endif
 uint8_t g_paletteRunTopLut [5] = { 0, 1, 1, 2, 2 };
 uint8_t g_paletteRunLeftLut[5] = { 0, 1, 2, 3, 4 };
+
+#if JVET_Q0806
+void initGeoTemplate()
+{
+  g_GeoParams = new int16_t*[GEO_NUM_PARTITION_MODE];
+  int modeIdx = 0;
+  for( int angleIdx = 0; angleIdx < GEO_NUM_ANGLES; angleIdx++ )
+  {
+    for( int distanceIdx = 0; distanceIdx < GEO_NUM_DISTANCES; distanceIdx++ )
+    {
+      if( (distanceIdx == 0 && angleIdx >= 16)
+        || ((distanceIdx == 2 || distanceIdx == 0) && (g_angle2mask[angleIdx] == 0 || g_angle2mask[angleIdx] == 5))
+        || g_angle2mask[angleIdx] == -1 )
+        continue;
+      g_GeoParams[modeIdx]    = new int16_t[2];
+      g_GeoParams[modeIdx][0] = (int16_t)angleIdx;
+      g_GeoParams[modeIdx][1] = (int16_t)distanceIdx;
+      modeIdx++;
+    }
+  }
+  for (int angleIdx = 0; angleIdx < (GEO_NUM_ANGLES >> 2) + 1; angleIdx++)
+  {
+    if (g_angle2mask[angleIdx] == -1)
+      continue;
+    g_globalGeoWeights[g_angle2mask[angleIdx]] = new int16_t[GEO_WEIGHT_MASK_SIZE * GEO_WEIGHT_MASK_SIZE];
+    g_globalGeoEncSADmask[g_angle2mask[angleIdx]] = new int16_t[GEO_WEIGHT_MASK_SIZE * GEO_WEIGHT_MASK_SIZE];
+  
+    int distanceX = angleIdx;
+    int distanceY = (distanceX + (GEO_NUM_ANGLES >> 2)) % GEO_NUM_ANGLES;
+    int16_t rho = (g_Dis[distanceX] << (GEO_MAX_CU_LOG2+1)) + (g_Dis[distanceY] << (GEO_MAX_CU_LOG2 + 1));
+    static const int16_t maskOffset = (2*GEO_MAX_CU_SIZE - GEO_WEIGHT_MASK_SIZE) >> 1;
+    int index = 0;
+    for( int y = 0; y < GEO_WEIGHT_MASK_SIZE; y++ )
+    {
+      int16_t lookUpY = (((y + maskOffset) << 1) + 1) * g_Dis[distanceY];
+      for( int x = 0; x < GEO_WEIGHT_MASK_SIZE; x++, index++ )
+      {
+        int16_t sx_i = ((x + maskOffset) << 1) + 1;
+        int16_t weightIdx = sx_i * g_Dis[distanceX] + lookUpY - rho;
+        int weightLinearIdx = 32 + weightIdx;
+        g_globalGeoWeights[g_angle2mask[angleIdx]][index] = Clip3(0, 8, (weightLinearIdx + 4) >> 3);
+        g_globalGeoEncSADmask[g_angle2mask[angleIdx]][index] = weightIdx > 0 ? 1 : 0;
+      }
+    }
+  }
+
+  for( int hIdx = 0; hIdx < GEO_NUM_CU_SIZE; hIdx++ )
+  {
+    int16_t height = 1 << ( hIdx + GEO_MIN_CU_LOG2);
+    for( int wIdx = 0; wIdx < GEO_NUM_CU_SIZE; wIdx++ )
+    {
+      int16_t width = 1 << (wIdx + GEO_MIN_CU_LOG2);
+      for( int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++ )
+      {
+        int16_t angle         = g_GeoParams[splitDir][0];
+        int16_t distance      = g_GeoParams[splitDir][1];
+        int16_t offsetX       = (GEO_WEIGHT_MASK_SIZE - width) >> 1;
+        int16_t offsetY       = (GEO_WEIGHT_MASK_SIZE - height) >> 1;
+        if( distance > 0 )
+        {
+          if( angle % 16 == 8 || (angle % 16 != 0 && height >= width) )
+          {
+            offsetY += angle < 16 ? ((distance * (int32_t)height) >> 3) : -((distance * (int32_t)height) >> 3);
+          }
+          else
+          {
+            offsetX += angle < 16 ? ((distance * (int32_t)width) >> 3) : -((distance * (int32_t)width) >> 3);
+          }
+        }
+        g_weightOffset[splitDir][hIdx][wIdx][0] = offsetX;
+        g_weightOffset[splitDir][hIdx][wIdx][1] = offsetY;
+      }
+    }
+  }
+}
+int16_t** g_GeoParams;
+int16_t*  g_globalGeoWeights   [GEO_NUM_PRESTORED_MASK];
+int16_t*  g_globalGeoEncSADmask[GEO_NUM_PRESTORED_MASK];
+int16_t   g_weightOffset       [GEO_NUM_PARTITION_MODE][GEO_NUM_CU_SIZE][GEO_NUM_CU_SIZE][2];
+int8_t    g_angle2mask[GEO_NUM_ANGLES] = { 0, -1, 1, 2, 3, 4, -1, -1, 5, -1, -1, 4, 3, 2, 1, -1, 0, -1, 1, 2, 3, 4, -1, -1, 5, -1, -1, 4, 3, 2, 1, -1 };
+int8_t    g_Dis[GEO_NUM_ANGLES] = { 8, 8, 8, 8, 4, 4, 2, 1, 0, -1, -2, -4, -4, -8, -8, -8, -8, -8, -8, -8, -4, -4, -2, -1, 0, 1, 2, 4, 4, 8, 8, 8 };
+int8_t    g_angle2mirror[GEO_NUM_ANGLES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2 };
+#endif
 //! \}
diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h
index 929a75547ef2cdafdc21e965dea0b93e8d3288e9..ecdbdd9bc79e9645352fc21264fa241d8685064a 100644
--- a/source/Lib/CommonLib/Rom.h
+++ b/source/Lib/CommonLib/Rom.h
@@ -205,20 +205,37 @@ constexpr uint8_t g_tbMax[257] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
 
 //! \}
 
+#if !JVET_Q0806
 extern       uint8_t g_triangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2];
 // 7-tap/3-tap, direction, 2/4/8/16/32/64/128
 extern int16_t *g_triangleWeights[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 2][MAX_CU_DEPTH - MIN_CU_LOG2 + 2];
+#endif
+
 extern bool g_mctsDecCheckEnabled;
 
 class  Mv;
 extern Mv   g_reusedUniMVs[32][32][8][8][2][33];
 extern bool g_isReusedUniMVsFilled[32][32][8][8];
 
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+extern uint16_t g_paletteQuant[57];
+#else
 extern const uint8_t g_paletteQuant[52];
+#endif
 extern uint8_t g_paletteRunTopLut[5];
 extern uint8_t g_paletteRunLeftLut[5];
 
 const int g_IBCBufferSize = 256 * 128;
 
+#if JVET_Q0806
+void initGeoTemplate();
+extern int16_t** g_GeoParams;
+extern int16_t*  g_globalGeoWeights   [GEO_NUM_PRESTORED_MASK];
+extern int16_t*  g_globalGeoEncSADmask[GEO_NUM_PRESTORED_MASK];
+extern int16_t   g_weightOffset       [GEO_NUM_PARTITION_MODE][GEO_NUM_CU_SIZE][GEO_NUM_CU_SIZE][2];
+extern int8_t    g_angle2mask         [GEO_NUM_ANGLES];
+extern int8_t    g_Dis[GEO_NUM_ANGLES];
+extern int8_t    g_angle2mirror[GEO_NUM_ANGLES];
+#endif
 #endif  //__TCOMROM__
 
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 7fec6a6f809b0bf3dbba633a3250a36fc8511516..b88b298b422c75cd951dd33b3c38207b92f5df4a 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -1785,7 +1785,11 @@ PicHeader::PicHeader()
 , m_disBdofFlag                                   ( 0 )
 , m_disDmvrFlag                                   ( 0 )
 , m_disProfFlag                                   ( 0 )
+#if !JVET_Q0806
 , m_maxNumTriangleCand                            ( 0 )
+#else
+, m_maxNumGeoCand                                 ( 0 )
+#endif
 , m_maxNumIBCMergeCand                            ( IBC_MRG_MAX_NUM_CANDS )
 , m_jointCbCrSignFlag                             ( 0 )
 , m_saoEnabledPresentFlag                         ( 0 )
@@ -1877,7 +1881,11 @@ void PicHeader::initPicHeader()
   m_disBdofFlag                                   = 0;
   m_disDmvrFlag                                   = 0;
   m_disProfFlag                                   = 0;
+#if !JVET_Q0806
   m_maxNumTriangleCand                            = 0;
+#else
+  m_maxNumGeoCand                                 = 0;
+#endif
   m_maxNumIBCMergeCand                            = IBC_MRG_MAX_NUM_CANDS;
   m_jointCbCrSignFlag                             = 0;
   m_saoEnabledPresentFlag                         = 0;
@@ -2017,7 +2025,11 @@ SPS::SPS()
 , m_AffineType                ( false )
 , m_PROF                      ( false )
 , m_ciip                   ( false )
+#if !JVET_Q0806
 , m_Triangle                  ( false )
+#else
+, m_Geo                       ( false )
+#endif
 #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
 , m_LadfEnabled               ( false )
 , m_LadfNumIntervals          ( 0 )
@@ -2232,7 +2244,11 @@ PPS::PPS()
 , m_PPSMvdL1ZeroIdc                  (0)
 , m_PPSCollocatedFromL0Idc           (0)
 , m_PPSSixMinusMaxNumMergeCandPlus1  (0)
+#if !JVET_Q0806
 , m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 (0)
+#else
+, m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 (0)
+#endif
 , m_cabacInitPresentFlag             (false)
 , m_pictureHeaderExtensionPresentFlag(0)
 , m_sliceHeaderExtensionPresentFlag  (false)
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index ed8df57a258124e71e14c2a1f71e8261607df05d..a63acb34898199c400553194de992b16a70f667e 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -267,7 +267,11 @@ class ConstraintInfo
   bool              m_noIbcConstraintFlag;
   bool              m_noCiipConstraintFlag;
   bool              m_noFPelMmvdConstraintFlag;
+#if !JVET_Q0806
   bool              m_noTriangleConstraintFlag;
+#else
+  bool              m_noGeoConstraintFlag;
+#endif
   bool              m_noLadfConstraintFlag;
   bool              m_noTransformSkipConstraintFlag;
   bool              m_noBDPCMConstraintFlag;
@@ -314,7 +318,11 @@ public:
     , m_noIbcConstraintFlag      (false)
     , m_noCiipConstraintFlag  (false)
     , m_noFPelMmvdConstraintFlag (false)
+#if !JVET_Q0806
     , m_noTriangleConstraintFlag (false)
+#else
+    , m_noGeoConstraintFlag      (false)
+#endif
     , m_noLadfConstraintFlag     (false)
     , m_noTransformSkipConstraintFlag(false)
     , m_noBDPCMConstraintFlag    (false)
@@ -401,8 +409,13 @@ public:
   void          setNoCiipConstraintFlag(bool bVal) { m_noCiipConstraintFlag = bVal; }
   bool          getNoFPelMmvdConstraintFlag() const { return m_noFPelMmvdConstraintFlag; }
   void          setNoFPelMmvdConstraintFlag(bool bVal) { m_noFPelMmvdConstraintFlag = bVal; }
+#if !JVET_Q0806
   bool          getNoTriangleConstraintFlag() const { return m_noTriangleConstraintFlag; }
   void          setNoTriangleConstraintFlag(bool bVal) { m_noTriangleConstraintFlag = bVal; }
+#else
+  bool          getNoGeoConstraintFlag() const { return m_noGeoConstraintFlag; }
+  void          setNoGeoConstraintFlag(bool bVal) { m_noGeoConstraintFlag = bVal; }
+#endif
   bool          getNoLadfConstraintFlag() const { return m_noLadfConstraintFlag; }
   void          setNoLadfConstraintFlag(bool bVal) { m_noLadfConstraintFlag = bVal; }
   bool          getNoTransformSkipConstraintFlag() const { return m_noTransformSkipConstraintFlag; }
@@ -1202,7 +1215,11 @@ private:
   bool              m_PROF;
   bool              m_bcw;                        //
   bool              m_ciip;
+#if !JVET_Q0806
   bool              m_Triangle;
+#else
+  bool              m_Geo;
+#endif
 #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
   bool              m_LadfEnabled;
   int               m_LadfNumIntervals;
@@ -1505,8 +1522,13 @@ void                    setCCALFEnabledFlag( bool b )
 
   void      setUseCiip         ( bool b )                                        { m_ciip = b; }
   bool      getUseCiip         ()                                      const     { return m_ciip; }
+#if !JVET_Q0806
   void      setUseTriangle        ( bool b )                                        { m_Triangle = b; }
   bool      getUseTriangle        ()                                      const     { return m_Triangle; }
+#else
+  void      setUseGeo             ( bool b )                                        { m_Geo = b; }
+  bool      getUseGeo             ()                                      const     { return m_Geo; }
+#endif
   void      setUseMRL             ( bool b )                                        { m_MRL = b; }
   bool      getUseMRL             ()                                      const     { return m_MRL; }
   void      setUseMIP             ( bool b )                                        { m_MIP = b; }
@@ -1641,7 +1663,11 @@ private:
   int               m_PPSMvdL1ZeroIdc;
   int               m_PPSCollocatedFromL0Idc;
   uint32_t          m_PPSSixMinusMaxNumMergeCandPlus1;
+#if !JVET_Q0806
   uint32_t          m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1;
+#else
+  uint32_t          m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1;
+#endif
 
   bool             m_cabacInitPresentFlag;
 
@@ -1849,8 +1875,13 @@ public:
   void                    setPPSCollocatedFromL0Idc(int u)                                { m_PPSCollocatedFromL0Idc = u;                 }
   uint32_t                getPPSSixMinusMaxNumMergeCandPlus1() const                      { return m_PPSSixMinusMaxNumMergeCandPlus1;     }
   void                    setPPSSixMinusMaxNumMergeCandPlus1(uint32_t u)                  { m_PPSSixMinusMaxNumMergeCandPlus1 = u;        }
+#if !JVET_Q0806
   uint32_t                getPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1() const       { return m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1; }
   void                    setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(uint32_t u)   { m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 = u; }
+#else
+  uint32_t                getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1() const            { return m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1; }
+  void                    setPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1(uint32_t u)        { m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 = u; }
+#endif
 
   void                   setCabacInitPresentFlag( bool flag )                             { m_cabacInitPresentFlag = flag;                }
   bool                   getCabacInitPresentFlag() const                                  { return m_cabacInitPresentFlag;                }
@@ -1996,7 +2027,11 @@ private:
   bool                        m_disBdofFlag;                                            //!< picture level BDOF disable flag
   bool                        m_disDmvrFlag;                                            //!< picture level DMVR disable flag
   bool                        m_disProfFlag;                                            //!< picture level PROF disable flag
+#if !JVET_Q0806
   uint32_t                    m_maxNumTriangleCand;                                     //!< max number of triangle merge candidates
+#else
+  uint32_t                    m_maxNumGeoCand;                                          //!< max number of geometric merge candidates
+#endif
   uint32_t                    m_maxNumIBCMergeCand;                                     //!< max number of IBC merge candidates
   bool                        m_jointCbCrSignFlag;                                      //!< joint Cb/Cr residual sign flag  
   bool                        m_saoEnabledPresentFlag;                                  //!< sao enabled flags present in the picture header
@@ -2116,8 +2151,13 @@ public:
   bool                        getDisDmvrFlag() const                                    { return m_disDmvrFlag;                                                                        }
   void                        setDisProfFlag( bool val )                                { m_disProfFlag = val;                                                                         }
   bool                        getDisProfFlag() const                                    { return m_disProfFlag;                                                                        }
+#if !JVET_Q0806
   void                        setMaxNumTriangleCand(uint32_t b)                         { m_maxNumTriangleCand = b;                                                                    }
   uint32_t                    getMaxNumTriangleCand() const                             { return m_maxNumTriangleCand;                                                                 }
+#else
+  void                        setMaxNumGeoCand(uint32_t b)                              { m_maxNumGeoCand = b; }
+  uint32_t                    getMaxNumGeoCand() const                                  { return m_maxNumGeoCand; }
+#endif
   void                        setMaxNumIBCMergeCand( uint32_t b )                       { m_maxNumIBCMergeCand = b;                                                                    }
   uint32_t                    getMaxNumIBCMergeCand() const                             { return m_maxNumIBCMergeCand;                                                                 } 
   void                        setJointCbCrSignFlag( bool b )                            { m_jointCbCrSignFlag = b;                                                                     }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 7ce3af5437c921ad2af97345bb829f6ddfb58621..0a264eb7c9b8bd13d6c398ee2fef2e8675bc5bb3 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_Q0446_MIP_CONST_SHIFT_OFFSET                 1 // JVET-Q0446: MIP with constant shift and offset
+
 #define JVET_Q0814_DPB                                    1 // JVET-Q0814: DPB capacity is based on picture units regardless of the resoltuion
 
 #define JVET_Q0820_ACT                                    1 // JVET-Q0820: ACT bug fixes and reversible ACT transform 
@@ -65,6 +67,8 @@
 
 #define JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU              1 // JVET-Q0501: Initialize palette predictor from above CTU row in WPP 
 
+#define JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX        1 // JVET-Q0503/Q0712: Platte encoder improvement/bugfix
+
 #define JVET_Q0819_PH_CHANGES                             1 // JVET-Q0819: Combination of PH related syntax changes
 
 #define JVET_Q0481_PARTITION_CONSTRAINTS_ORDER            1 // JVET-Q0481: Ordering of partition constraints syntax elements in the SPS
@@ -97,6 +101,9 @@
 #define JVET_Q0483_CLIP_TMVP                              1 // JVET-Q0483: Clip TMVP when no scaling is applied
 
 #define JVET_Q0516_MTS_SIGNALLING_DC_ONLY_COND            1 // JVET-Q0516/Q0685: disable MTS when there is only DC coefficient 
+
+#define JVET_Q0806                                        1 // Geo related adoptions (JVET-Q0059, JVET-Q0077, JVET-Q0123, JVET-Q0188, JVET-Q0242_GEO, JVET-Q0309, JVET-Q0365 and JVET-Q0370)
+
 #define JVET_Q0055_MTS_SIGNALLING                         1 // JVET-Q0055: Check for transform coefficients outside the 16x16 area
 #define JVET_Q0480_RASTER_RECT_SLICES                     1 // JVET-Q0480: Eliminate redundant slice height syntax when in raster rectangular slice mode (tile_idx_delta_present_flag == 0)
 
@@ -106,6 +113,8 @@
 
 #define JVET_Q0487_SCALING_WINDOW_ISSUES                  1 // JVET-Q0487: Fix scaling window issues when scaling ratio is 1:1
 
+#define JVET_Q0787_SUBPIC                                 1 // JVET-Q0787: fix subpicture location signalling
+
 #define JVET_AHG14_LOSSLESS                               1
 #define JVET_AHG14_LOSSLESS_ENC_QP_FIX                    1 && JVET_AHG14_LOSSLESS
 
@@ -602,7 +611,12 @@ enum DFunc
 
   DF_SAD_INTERMEDIATE_BITDEPTH = 63,
 
+#if JVET_Q0806
+  DF_SAD_WITH_MASK   = 64,
+  DF_TOTAL_FUNCTIONS = 65
+#else
   DF_TOTAL_FUNCTIONS = 64
+#endif
 };
 
 /// motion vector predictor direction used in AMVP
@@ -880,12 +894,14 @@ enum MergeType
   NUM_MRG_TYPE                   // 5
 };
 
+#if !JVET_Q0806
 enum TriangleSplit
 {
   TRIANGLE_DIR_135 = 0,
   TRIANGLE_DIR_45,
   TRIANGLE_DIR_NUM
 };
+#endif
 
 //////////////////////////////////////////////////////////////////////////
 // Encoder modes to try out
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 041b241b8e494577d48561d1af13d8cc07b6e6bb..8a6d7c8d6af9f7ffacf47eff65c8cbf0d2b1d45c 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -266,7 +266,11 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
   affine            = other.affine;
   affineType        = other.affineType;
   colorTransform = other.colorTransform;
+#if !JVET_Q0806
   triangle          = other.triangle;
+#else
+  geoFlag           = other.geoFlag;
+#endif
   bdpcmMode         = other.bdpcmMode;
   bdpcmModeChroma   = other.bdpcmModeChroma;
   qp                = other.qp;
@@ -326,7 +330,11 @@ void CodingUnit::initData()
   affine            = false;
   affineType        = 0;
   colorTransform = false;
+#if !JVET_Q0806
   triangle          = false;
+#else
+  geoFlag           = false;
+#endif
   bdpcmMode         = 0;
   bdpcmModeChroma   = 0;
   qp                = 0;
@@ -458,10 +466,12 @@ const uint8_t CodingUnit::checkAllowedSbt() const
   {
     return 0;
   }
+#if !JVET_Q0806
   if( triangle )
   {
     return 0;
   }
+#endif
 
   uint8_t sbtAllowed = 0;
   int cuWidth  = lwidth();
@@ -528,9 +538,15 @@ void PredictionUnit::initData()
   mergeFlag   = false;
   regularMergeFlag = false;
   mergeIdx    = MAX_UCHAR;
+#if !JVET_Q0806
   triangleSplitDir  = MAX_UCHAR;
   triangleMergeIdx0 = MAX_UCHAR;
   triangleMergeIdx1 = MAX_UCHAR;
+#else
+  geoSplitDir  = MAX_UCHAR;
+  geoMergeIdx0 = MAX_UCHAR;
+  geoMergeIdx1 = MAX_UCHAR;
+#endif
   mmvdMergeFlag = false;
   mmvdMergeIdx = MAX_UINT;
   interDir    = MAX_UCHAR;
@@ -579,9 +595,15 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData)
   mergeFlag   = predData.mergeFlag;
   regularMergeFlag = predData.regularMergeFlag;
   mergeIdx    = predData.mergeIdx;
+#if !JVET_Q0806
   triangleSplitDir  = predData.triangleSplitDir  ;
   triangleMergeIdx0 = predData.triangleMergeIdx0 ;
   triangleMergeIdx1 = predData.triangleMergeIdx1 ;
+#else
+  geoSplitDir  = predData.geoSplitDir;
+  geoMergeIdx0 = predData.geoMergeIdx0;
+  geoMergeIdx1 = predData.geoMergeIdx1;
+#endif
   mmvdMergeFlag = predData.mmvdMergeFlag;
   mmvdMergeIdx = predData.mmvdMergeIdx;
   interDir    = predData.interDir;
@@ -625,9 +647,15 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
   mergeFlag   = other.mergeFlag;
   regularMergeFlag = other.regularMergeFlag;
   mergeIdx    = other.mergeIdx;
+#if !JVET_Q0806
   triangleSplitDir  = other.triangleSplitDir  ;
   triangleMergeIdx0 = other.triangleMergeIdx0 ;
   triangleMergeIdx1 = other.triangleMergeIdx1 ;
+#else
+  geoSplitDir  = other.geoSplitDir;
+  geoMergeIdx0 = other.geoMergeIdx0;
+  geoMergeIdx1 = other.geoMergeIdx1;
+#endif
   mmvdMergeFlag = other.mmvdMergeFlag;
   mmvdMergeIdx = other.mmvdMergeIdx;
   interDir    = other.interDir;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 91130a7221d62eb12ddbc15dbdbfa5d5caccd706..b8c2a30c788912fc00960cb7ae0067fe364c8279 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -309,7 +309,11 @@ struct CodingUnit : public UnitArea
   bool           affine;
   int            affineType;
   bool           colorTransform;
+#if !JVET_Q0806
   bool           triangle;
+#else
+  bool           geoFlag;
+#endif
   int            bdpcmMode;
   int            bdpcmModeChroma;
   uint8_t          imv;
@@ -383,9 +387,15 @@ struct InterPredictionData
   bool      mergeFlag;
   bool      regularMergeFlag;
   uint8_t     mergeIdx;
+#if !JVET_Q0806
   uint8_t     triangleSplitDir;
   uint8_t     triangleMergeIdx0;
   uint8_t     triangleMergeIdx1;
+#else
+  uint8_t     geoSplitDir;
+  uint8_t     geoMergeIdx0;
+  uint8_t     geoMergeIdx1;
+#endif
   bool           mmvdMergeFlag;
   uint32_t       mmvdMergeIdx;
   uint8_t     interDir;
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 7dae6ae23dc5e80a70fa1075dc85359a119c1ee8..ece0dcac644277fafe8574191a23578ac51bf69a 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -244,7 +244,11 @@ void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone )
 {
   const PredictionUnit& pu = *cu.firstPU;
 
+#if !JVET_Q0806
   if (!cu.triangle && !cu.affine && !isToBeDone )
+#else
+  if (!cu.geoFlag && !cu.affine && !isToBeDone)
+#endif
   {
     MotionInfo mi = pu.getMotionInfo();
 
@@ -3192,6 +3196,7 @@ void PU::restrictBiPredMergeCandsOne(PredictionUnit &pu)
   }
 }
 
+#if !JVET_Q0806
 void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangleMrgCtx )
 {
   MergeCtx tmpMergeCtx;
@@ -3348,6 +3353,167 @@ int32_t PU::mappingRefPic( const PredictionUnit &pu, int32_t refPicPoc, bool tar
   }
   return -1;
 }
+#else
+void PU::getGeoMergeCandidates( const PredictionUnit &pu, MergeCtx& geoMrgCtx )
+{
+  MergeCtx tmpMergeCtx;
+
+  const Slice &slice = *pu.cs->slice;
+  const uint32_t maxNumMergeCand = slice.getPicHeader()->getMaxNumMergeCand();
+
+  geoMrgCtx.numValidMergeCand = 0;
+
+  for (int32_t i = 0; i < GEO_MAX_NUM_UNI_CANDS; i++)
+  {
+    geoMrgCtx.BcwIdx[i] = BCW_DEFAULT;
+    geoMrgCtx.interDirNeighbours[i] = 0;
+    geoMrgCtx.mrgTypeNeighbours[i] = MRG_TYPE_DEFAULT_N;
+    geoMrgCtx.mvFieldNeighbours[(i << 1)].refIdx = NOT_VALID;
+    geoMrgCtx.mvFieldNeighbours[(i << 1) + 1].refIdx = NOT_VALID;
+    geoMrgCtx.mvFieldNeighbours[(i << 1)].mv = Mv();
+    geoMrgCtx.mvFieldNeighbours[(i << 1) + 1].mv = Mv();
+    geoMrgCtx.useAltHpelIf[i] = false;
+  }
+
+  PU::getInterMergeCandidates(pu, tmpMergeCtx, 0);
+
+  for (int32_t i = 0; i < maxNumMergeCand; i++)
+  {
+    int parity = i & 1;
+    if( tmpMergeCtx.interDirNeighbours[i] & (0x01 + parity) )
+    {
+      geoMrgCtx.interDirNeighbours[geoMrgCtx.numValidMergeCand] = 1 + parity;
+      geoMrgCtx.mrgTypeNeighbours[geoMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + !parity].mv = Mv(0, 0);
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].mv;
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + !parity].refIdx = -1;
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].refIdx;
+      geoMrgCtx.numValidMergeCand++;
+      if (geoMrgCtx.numValidMergeCand == GEO_MAX_NUM_UNI_CANDS)
+      {
+        return;
+      }
+      continue;
+    }
+
+    if (tmpMergeCtx.interDirNeighbours[i] & (0x02 - parity))
+    {
+      geoMrgCtx.interDirNeighbours[geoMrgCtx.numValidMergeCand] = 2 - parity;
+      geoMrgCtx.mrgTypeNeighbours[geoMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + !parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].mv;
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].mv = Mv(0, 0);
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + !parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].refIdx;
+      geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].refIdx = -1;
+      geoMrgCtx.numValidMergeCand++;
+      if (geoMrgCtx.numValidMergeCand == GEO_MAX_NUM_UNI_CANDS)
+      {
+        return;
+      }
+    }
+  }
+}
+
+void PU::spanGeoMotionInfo( PredictionUnit &pu, MergeCtx &geoMrgCtx, const uint8_t splitDir, const uint8_t candIdx0, const uint8_t candIdx1)
+{
+  pu.geoSplitDir  = splitDir;
+  pu.geoMergeIdx0 = candIdx0;
+  pu.geoMergeIdx1 = candIdx1;
+  MotionBuf mb = pu.getMotionBuf();
+
+  MotionInfo biMv;
+  biMv.isInter  = true;
+  biMv.sliceIdx = pu.cs->slice->getIndependentSliceIdx();
+
+  if( geoMrgCtx.interDirNeighbours[candIdx0] == 1 && geoMrgCtx.interDirNeighbours[candIdx1] == 2 )
+  {
+    biMv.interDir  = 3;
+    biMv.mv[0]     = geoMrgCtx.mvFieldNeighbours[ candIdx0 << 1     ].mv;
+    biMv.mv[1]     = geoMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv;
+    biMv.refIdx[0] = geoMrgCtx.mvFieldNeighbours[ candIdx0 << 1     ].refIdx;
+    biMv.refIdx[1] = geoMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx;
+  }
+  else if( geoMrgCtx.interDirNeighbours[candIdx0] == 2 && geoMrgCtx.interDirNeighbours[candIdx1] == 1 )
+  {
+    biMv.interDir  = 3;
+    biMv.mv[0]     = geoMrgCtx.mvFieldNeighbours[ candIdx1 << 1     ].mv;
+    biMv.mv[1]     = geoMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv;
+    biMv.refIdx[0] = geoMrgCtx.mvFieldNeighbours[ candIdx1 << 1     ].refIdx;
+    biMv.refIdx[1] = geoMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx;
+  }
+  else if( geoMrgCtx.interDirNeighbours[candIdx0] == 1 && geoMrgCtx.interDirNeighbours[candIdx1] == 1 )
+  {
+    biMv.interDir = 1;
+    biMv.mv[0] = geoMrgCtx.mvFieldNeighbours[candIdx1 << 1].mv;
+    biMv.mv[1] = Mv(0, 0);
+    biMv.refIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx1 << 1].refIdx;
+    biMv.refIdx[1] = -1;
+  }
+  else if( geoMrgCtx.interDirNeighbours[candIdx0] == 2 && geoMrgCtx.interDirNeighbours[candIdx1] == 2 )
+  {
+    biMv.interDir = 2;
+    biMv.mv[0] = Mv(0, 0);
+    biMv.mv[1] = geoMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv;
+    biMv.refIdx[0] = -1;
+    biMv.refIdx[1] = geoMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx;
+  }
+
+  int16_t angle = g_GeoParams[splitDir][0];
+  int tpmMask = 0;
+  int lookUpY = 0, motionIdx = 0;
+  bool isFlip = angle >= 13 && angle <= 27;
+  int distanceIdx = g_GeoParams[splitDir][1];
+  int distanceX = angle;
+  int distanceY = (distanceX + (GEO_NUM_ANGLES >> 2)) % GEO_NUM_ANGLES;
+  int offsetX = (-(int)pu.lwidth()) >> 1;
+  int offsetY = (-(int)pu.lheight()) >> 1;
+  if (distanceIdx > 0)
+  {
+    if (angle % 16 == 8 || (angle % 16 != 0 && pu.lheight() >= pu.lwidth()))
+      offsetY += angle < 16 ? ((distanceIdx * pu.lheight()) >> 3) : -(int)((distanceIdx * pu.lheight()) >> 3);
+    else
+      offsetX += angle < 16 ? ((distanceIdx * pu.lwidth()) >> 3) : -(int)((distanceIdx * pu.lwidth()) >> 3);
+  }
+  for (int y = 0; y < mb.height; y++)
+  {
+    lookUpY = (((4 * y + offsetY) << 1) + 5) * g_Dis[distanceY];
+    for (int x = 0; x < mb.width; x++)
+    {
+      motionIdx = (((4 * x + offsetX) << 1) + 5) * g_Dis[distanceX] + lookUpY;
+      tpmMask = abs(motionIdx) < 32 ? 2 : (motionIdx <= 0 ? (1 - isFlip) : isFlip);
+      if (tpmMask == 2)
+      {
+        mb.at(x, y).isInter = true;
+        mb.at(x, y).interDir = biMv.interDir;
+        mb.at(x, y).refIdx[0] = biMv.refIdx[0];
+        mb.at(x, y).refIdx[1] = biMv.refIdx[1];
+        mb.at(x, y).mv[0] = biMv.mv[0];
+        mb.at(x, y).mv[1] = biMv.mv[1];
+        mb.at(x, y).sliceIdx = biMv.sliceIdx;
+      }
+      else if (tpmMask == 0)
+      {
+        mb.at(x, y).isInter = true;
+        mb.at(x, y).interDir = geoMrgCtx.interDirNeighbours[candIdx0];
+        mb.at(x, y).refIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx0 << 1].refIdx;
+        mb.at(x, y).refIdx[1] = geoMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx;
+        mb.at(x, y).mv[0] = geoMrgCtx.mvFieldNeighbours[candIdx0 << 1].mv;
+        mb.at(x, y).mv[1] = geoMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv;
+        mb.at(x, y).sliceIdx = biMv.sliceIdx;
+      }
+      else
+      {
+        mb.at(x, y).isInter = true;
+        mb.at(x, y).interDir = geoMrgCtx.interDirNeighbours[candIdx1];
+        mb.at(x, y).refIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx1 << 1].refIdx;
+        mb.at(x, y).refIdx[1] = geoMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx;
+        mb.at(x, y).mv[0] = geoMrgCtx.mvFieldNeighbours[candIdx1 << 1].mv;
+        mb.at(x, y).mv[1] = geoMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv;
+        mb.at(x, y).sliceIdx = biMv.sliceIdx;
+      }
+    }
+  }
+}
+#endif
 
 bool CU::hasSubCUNonZeroMVd( const CodingUnit& cu )
 {
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 8cead3c5ca37492e67158b262460de667902203f..e13475ef6c10886d9562969009bae48d6abc9ca5 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -168,9 +168,14 @@ namespace PU
   bool isLMCMode                      (                          unsigned mode);
   bool isLMCModeEnabled               (const PredictionUnit &pu, unsigned mode);
   bool isChromaIntraModeCrossCheckMode(const PredictionUnit &pu);
+#if !JVET_Q0806
   void getTriangleMergeCandidates     (const PredictionUnit &pu, MergeCtx &triangleMrgCtx);
   void spanTriangleMotionInfo         (      PredictionUnit &pu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1);
   int32_t mappingRefPic               (const PredictionUnit &pu, int32_t refPicPoc, bool targetRefPicList);
+#else
+  void getGeoMergeCandidates          (const PredictionUnit &pu, MergeCtx &GeoMrgCtx);
+  void spanGeoMotionInfo              (      PredictionUnit &pu, MergeCtx &GeoMrgCtx, const uint8_t splitDir, const uint8_t candIdx0, const uint8_t candIdx1);
+#endif
   bool isAddNeighborMv  (const Mv& currMv, Mv* neighborMvs, int numNeighborMv);
   void getIbcMVPsEncOnly(PredictionUnit &pu, Mv* mvPred, int& nbPred);
   bool getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv);
diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.cpp b/source/Lib/CommonLib/dtrace_blockstatistics.cpp
index 8005a537f23095a2ca901a3d95414f68ecd3dccc..4338f027a3c0bf232b570e25cc6bc686fc532a7f 100644
--- a/source/Lib/CommonLib/dtrace_blockstatistics.cpp
+++ b/source/Lib/CommonLib/dtrace_blockstatistics.cpp
@@ -271,6 +271,7 @@ void CDTrace::dtrace_polygon_vector(int k, int poc, const std::vector<Position>
   dtrace<false>(k, "BlockStat: POC %d @[%s] %s={%4d,%4d}\n", poc, polygonDescription.c_str(), stat_type.c_str(), val_x, val_y);
 }
 
+#if !JVET_Q0806
 void retrieveTriangularMvInfo(const PredictionUnit& pu, MotionInfo& mi0, MotionInfo& mi1)
 {
   int triangleDir = pu.triangleSplitDir;
@@ -358,6 +359,7 @@ void retrieveTrianglePolygon(const PredictionUnit& pu, std::vector<Position>& tr
     CHECK(triangleDir != TRIANGLE_DIR_45 && triangleDir != TRIANGLE_DIR_135, "Unknown triangle type");
   }
 }
+#endif
 
 void writeBlockStatisticsHeader(const SPS *sps)
 {
@@ -493,7 +495,11 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea)
               DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, pu, GetBlockStatisticName(BlockStatistic::MVPIdxL1), pu.mvpIdx[REF_PIC_LIST_1]);
               DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, pu, GetBlockStatisticName(BlockStatistic::RefIdxL1), pu.refIdx[REF_PIC_LIST_1]);
             }
+#if !JVET_Q0806
             if (!pu.cu->affine && !pu.cu->triangle)
+#else
+            if (!pu.cu->affine && !pu.cu->geoFlag)
+#endif
             {
               if (pu.interDir != 2 /* PRED_L1 */)
               {
@@ -518,6 +524,7 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea)
                 DTRACE_BLOCK_VECTOR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, pu, GetBlockStatisticName(BlockStatistic::MVL1), mv.hor, mv.ver);
               }
             }
+#if !JVET_Q0806
             else if (pu.cu->triangle)
             {
               MotionInfo mi[2];
@@ -539,6 +546,7 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea)
                 }
               }
             }
+#endif
             else
             {
               if (pu.interDir != 2 /* PRED_L1 */)
@@ -864,7 +872,11 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea)
               DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::MVPIdxL1), pu.mvpIdx[REF_PIC_LIST_1]);
               DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::RefIdxL1), pu.refIdx[REF_PIC_LIST_1]);
             }
+#if !JVET_Q0806
             if (!pu.cu->affine && !pu.cu->triangle)
+#else
+            if (!pu.cu->affine && !pu.cu->geoFlag)
+#endif
             {
               if (pu.interDir != 2 /* PRED_L1 */)
               {
@@ -889,6 +901,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea)
                 DTRACE_BLOCK_VECTOR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::MVL1), mv.hor, mv.ver);
               }
             }
+#if !JVET_Q0806
             else if (pu.cu->triangle)
             {
               MotionInfo mi[2];
@@ -910,6 +923,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea)
                 }
               }
             }
+#endif
             else
             {
               if (pu.interDir != 2 /* PRED_L1 */)
diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.h b/source/Lib/CommonLib/dtrace_blockstatistics.h
index 2df8b9b3af20416ee918590671b48f374c40f1d9..c692bbb3027141fa775f9675038c63f3e444a790 100644
--- a/source/Lib/CommonLib/dtrace_blockstatistics.h
+++ b/source/Lib/CommonLib/dtrace_blockstatistics.h
@@ -118,9 +118,15 @@ enum class BlockStatistic {
   MMVDMergeIdx,
   CiipFlag,
   SMVDFlag,
+#if !JVET_Q0806
   TrianglePartitioning,
   TriangleMVL0, //<< currently only uni-prediction enabled
   TriangleMVL1, //<< currently only uni-prediction enabled
+#else
+  GeoPartitioning,
+  GeoMVL0, //<< currently only uni-prediction enabled
+  GeoMVL1, //<< currently only uni-prediction enabled
+#endif
   BCWIndex,
 // for dual tree
   // general
@@ -212,10 +218,16 @@ static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType
   { BlockStatistic::MMVDMergeIdx,           std::tuple<std::string, BlockStatisticType, std::string>{"MMVDMergeIdx",                BlockStatisticType::Integer,                "[0, 1]"}},
   { BlockStatistic::CiipFlag,            std::tuple<std::string, BlockStatisticType, std::string>{"CiipFlag",                 BlockStatisticType::Flag,                   ""}},
   { BlockStatistic::SMVDFlag,               std::tuple<std::string, BlockStatisticType, std::string>{"SMVDFlag",                    BlockStatisticType::Flag,                   ""}},
+#if !JVET_Q0806
   { BlockStatistic::TrianglePartitioning,   std::tuple<std::string, BlockStatisticType, std::string>{"TrianglePartitioning",        BlockStatisticType::Line,                   ""}},
   { BlockStatistic::TriangleMVL0,           std::tuple<std::string, BlockStatisticType, std::string>{"TriangleMVL0",                BlockStatisticType::VectorPolygon,          "Scale: 4"}},
   { BlockStatistic::TriangleMVL1,           std::tuple<std::string, BlockStatisticType, std::string>{"TriangleMVL1",                BlockStatisticType::VectorPolygon,          "Scale: 4"}},
-  { BlockStatistic::BCWIndex,               std::tuple<std::string, BlockStatisticType, std::string>{"BCWIndex",                    BlockStatisticType::Integer,                "[0, 4]"}},
+#else
+  { BlockStatistic::GeoPartitioning,        std::tuple<std::string, BlockStatisticType, std::string>{"GeoPartitioning",             BlockStatisticType::Line,                   ""} },
+  { BlockStatistic::GeoMVL0,                std::tuple<std::string, BlockStatisticType, std::string>{"GeoMVL0",                     BlockStatisticType::VectorPolygon,          "Scale: 4"} },
+  { BlockStatistic::GeoMVL1,                std::tuple<std::string, BlockStatisticType, std::string>{"GeoMVL1",                     BlockStatisticType::VectorPolygon,          "Scale: 4"} },
+#endif
+  { BlockStatistic::BCWIndex,               std::tuple<std::string, BlockStatisticType, std::string>{"BCWIndex",                    BlockStatisticType::Integer,                "[0, 4]"} },
   // for dual tree
   { BlockStatistic::Depth_Chroma,                  std::tuple<std::string, BlockStatisticType, std::string>{"Depth_Chroma",                       BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
   { BlockStatistic::QT_Depth_Chroma,               std::tuple<std::string, BlockStatisticType, std::string>{"QT_Depth_Chroma",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
diff --git a/source/Lib/CommonLib/x86/InterpolationFilterX86.h b/source/Lib/CommonLib/x86/InterpolationFilterX86.h
index 2b5bda2df04e9ae2626a74e1696069675ad41aa8..81608d2a4da059975fd7a81eeb09170b82b0dcc5 100644
--- a/source/Lib/CommonLib/x86/InterpolationFilterX86.h
+++ b/source/Lib/CommonLib/x86/InterpolationFilterX86.h
@@ -1327,6 +1327,7 @@ static void simdFilter( const ClpRng& clpRng, Pel const *src, int srcStride, Pel
   }
 }
 
+#if !JVET_Q0806
 template< X86_VEXT vext >
 void xWeightedTriangleBlk_SSE(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
 {
@@ -1449,6 +1450,227 @@ void xWeightedTriangleBlk_SSE(const PredictionUnit &pu, const uint32_t width, co
     }
   }
 }
+#else
+template< X86_VEXT vext >
+void xWeightedGeoBlk_SSE(const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const uint8_t splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1)
+{
+  Pel* dst = predDst.get(compIdx).buf;
+  Pel* src0 = predSrc0.get(compIdx).buf;
+  Pel* src1 = predSrc1.get(compIdx).buf;
+  int32_t strideDst = predDst.get(compIdx).stride;
+  int32_t strideSrc0 = predSrc0.get(compIdx).stride;
+  int32_t strideSrc1 = predSrc1.get(compIdx).stride;
+
+  const char    log2WeightBase = 3;
+  const ClpRng  clpRng = pu.cu->slice->clpRngs().comp[compIdx];
+  const int32_t shiftWeighted = std::max<int>(2, (IF_INTERNAL_PREC - clpRng.bd)) + log2WeightBase;
+  const int32_t offsetWeighted = (1 << (shiftWeighted - 1)) + (IF_INTERNAL_OFFS << log2WeightBase);
+
+  int16_t wIdx = floorLog2(pu.lwidth()) - GEO_MIN_CU_LOG2;
+  int16_t hIdx = floorLog2(pu.lheight()) - GEO_MIN_CU_LOG2;
+  int16_t angle = g_GeoParams[splitDir][0];
+  int16_t stepY = 0;
+  int16_t* weight = nullptr;
+  if (g_angle2mirror[angle] == 2)
+  {
+    stepY = -GEO_WEIGHT_MASK_SIZE;
+    weight = &g_globalGeoWeights[g_angle2mask[angle]][(GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][1]) * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+  }
+  else if (g_angle2mirror[angle] == 1)
+  {
+    stepY = GEO_WEIGHT_MASK_SIZE;
+    weight = &g_globalGeoWeights[g_angle2mask[angle]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + (GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][0])];
+  }
+  else
+  {
+    stepY = GEO_WEIGHT_MASK_SIZE;
+    weight = &g_globalGeoWeights[g_angle2mask[angle]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+  }
+
+  const __m128i mmEight = _mm_set1_epi16(8);
+  const __m128i mmOffset = _mm_set1_epi32(offsetWeighted);
+  const __m128i mmShift = _mm_cvtsi32_si128(shiftWeighted);
+  const __m128i mmMin = _mm_set1_epi16(clpRng.min);
+  const __m128i mmMax = _mm_set1_epi16(clpRng.max);
+
+  if (compIdx != COMPONENT_Y && pu.chromaFormat == CHROMA_420)
+    stepY <<= 1;
+  if (width == 4)
+  {
+    // it will occur to chroma only
+    for (int y = 0; y < height; y++)
+    {
+      __m128i s0 = _mm_loadl_epi64((__m128i *) (src0));
+      __m128i s1 = _mm_loadl_epi64((__m128i *) (src1));
+      __m128i w0;
+      if (g_angle2mirror[angle] == 1)
+      {
+        w0 = _mm_loadu_si128((__m128i *) (weight - (8 - 1)));
+        const __m128i shuffle_mask = _mm_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+        w0 = _mm_shuffle_epi8(w0, shuffle_mask);
+      }
+      else
+      {
+        w0 = _mm_loadu_si128((__m128i *) (weight));
+      }
+      w0 = _mm_shuffle_epi8(w0, _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0));
+      __m128i w1 = _mm_sub_epi16(mmEight, w0);
+      s0 = _mm_unpacklo_epi16(s0, s1);
+      w0 = _mm_unpacklo_epi16(w0, w1);
+      s0 = _mm_add_epi32(_mm_madd_epi16(s0, w0), mmOffset);
+      s0 = _mm_sra_epi32(s0, mmShift);
+      s0 = _mm_packs_epi32(s0, s0);
+      s0 = _mm_min_epi16(mmMax, _mm_max_epi16(s0, mmMin));
+      _mm_storel_epi64((__m128i *) (dst), s0);
+      dst += strideDst;
+      src0 += strideSrc0;
+      src1 += strideSrc1;
+      weight += stepY;
+    }
+  }
+#if USE_AVX2
+  else if (width >= 16)
+  {
+    const __m256i mmEightAVX2 = _mm256_set1_epi16(8);
+    const __m256i mmOffsetAVX2 = _mm256_set1_epi32(offsetWeighted);
+    const __m256i mmMinAVX2 = _mm256_set1_epi16(clpRng.min);
+    const __m256i mmMaxAVX2 = _mm256_set1_epi16(clpRng.max);
+    for (int y = 0; y < height; y++)
+    {
+      for (int x = 0; x < width; x += 16)
+      {
+        __m256i s0 = _mm256_lddqu_si256((__m256i *) (src0 + x)); // why not aligned with 128/256 bit boundaries
+        __m256i s1 = _mm256_lddqu_si256((__m256i *) (src1 + x));
+
+        __m256i w0 = _mm256_lddqu_si256((__m256i *) (weight + x));
+        if (compIdx != COMPONENT_Y &&  pu.chromaFormat != CHROMA_444)
+        {
+          const __m256i mask = _mm256_set_epi16(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1);
+          __m256i w0p0, w0p1;
+          if (g_angle2mirror[angle] == 1)
+          {
+            w0p0 = _mm256_lddqu_si256((__m256i *) (weight - (x << 1) - (16 - 1))); // first sub-sample the required weights.
+            w0p1 = _mm256_lddqu_si256((__m256i *) (weight - (x << 1) - 16 - (16 - 1)));
+            const __m256i shuffle_mask = _mm256_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+            w0p0 = _mm256_shuffle_epi8(w0p0, shuffle_mask);
+            w0p0 = _mm256_permute4x64_epi64(w0p0, _MM_SHUFFLE(1, 0, 3, 2));
+            w0p1 = _mm256_shuffle_epi8(w0p1, shuffle_mask);
+            w0p1 = _mm256_permute4x64_epi64(w0p1, _MM_SHUFFLE(1, 0, 3, 2));
+          }
+          else
+          {
+            w0p0 = _mm256_lddqu_si256((__m256i *) (weight + (x << 1))); // first sub-sample the required weights.
+            w0p1 = _mm256_lddqu_si256((__m256i *) (weight + (x << 1) + 16));
+          }
+          w0p0 = _mm256_mullo_epi16(w0p0, mask);
+          w0p1 = _mm256_mullo_epi16(w0p1, mask);
+          w0 = _mm256_packs_epi16(w0p0, w0p1);
+          w0 = _mm256_permute4x64_epi64(w0, _MM_SHUFFLE(3, 1, 2, 0));
+        }
+        else
+        {
+          if (g_angle2mirror[angle] == 1)
+          {
+            w0 = _mm256_lddqu_si256((__m256i *) (weight - x - (16 - 1)));
+            const __m256i shuffle_mask = _mm256_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+            w0 = _mm256_shuffle_epi8(w0, shuffle_mask);
+            w0 = _mm256_permute4x64_epi64(w0, _MM_SHUFFLE(1, 0, 3, 2));
+          }
+          else
+          {
+            w0 = _mm256_lddqu_si256((__m256i *) (weight + x));
+          }
+        }
+        __m256i w1 = _mm256_sub_epi16(mmEightAVX2, w0);
+
+        __m256i s0tmp = _mm256_unpacklo_epi16(s0, s1);
+        __m256i w0tmp = _mm256_unpacklo_epi16(w0, w1);
+        s0tmp = _mm256_add_epi32(_mm256_madd_epi16(s0tmp, w0tmp), mmOffsetAVX2);
+        s0tmp = _mm256_sra_epi32(s0tmp, mmShift);
+
+        s0 = _mm256_unpackhi_epi16(s0, s1);
+        w0 = _mm256_unpackhi_epi16(w0, w1);
+        s0 = _mm256_add_epi32(_mm256_madd_epi16(s0, w0), mmOffsetAVX2);
+        s0 = _mm256_sra_epi32(s0, mmShift);
+
+        s0 = _mm256_packs_epi32(s0tmp, s0);
+        s0 = _mm256_min_epi16(mmMaxAVX2, _mm256_max_epi16(s0, mmMinAVX2));
+        _mm256_storeu_si256((__m256i *) (dst + x), s0);
+      }
+      dst += strideDst;
+      src0 += strideSrc0;
+      src1 += strideSrc1;
+      weight += stepY;
+    }
+  }
+#endif
+  else
+  {
+    for (int y = 0; y < height; y++)
+    {
+      for (int x = 0; x < width; x += 8)
+      {
+        __m128i s0 = _mm_lddqu_si128((__m128i *) (src0 + x));
+        __m128i s1 = _mm_lddqu_si128((__m128i *) (src1 + x));
+        __m128i w0;
+        if (compIdx != COMPONENT_Y && pu.chromaFormat != CHROMA_444)
+        {
+          const __m128i mask = _mm_set_epi16(0, 1, 0, 1, 0, 1, 0, 1);
+          __m128i w0p0, w0p1;
+          if (g_angle2mirror[angle] == 1)
+          {
+            w0p0 = _mm_lddqu_si128((__m128i *) (weight - (x << 1) - (8 - 1))); // first sub-sample the required weights.
+            w0p1 = _mm_lddqu_si128((__m128i *) (weight - (x << 1) - 8 - (8 - 1)));
+            const __m128i shuffle_mask = _mm_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+            w0p0 = _mm_shuffle_epi8(w0p0, shuffle_mask);
+            w0p1 = _mm_shuffle_epi8(w0p1, shuffle_mask);
+          }
+          else
+          {
+            w0p0 = _mm_lddqu_si128((__m128i *) (weight + (x << 1))); // first sub-sample the required weights.
+            w0p1 = _mm_lddqu_si128((__m128i *) (weight + (x << 1) + 8));
+          }
+          w0p0 = _mm_mullo_epi16(w0p0, mask);
+          w0p1 = _mm_mullo_epi16(w0p1, mask);
+          w0 = _mm_packs_epi32(w0p0, w0p1);
+        }
+        else
+        {
+          if (g_angle2mirror[angle] == 1)
+          {
+            w0 = _mm_lddqu_si128((__m128i *) (weight - x - (8 - 1)));
+            const __m128i shuffle_mask = _mm_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+            w0 = _mm_shuffle_epi8(w0, shuffle_mask);
+          }
+          else
+          {
+            w0 = _mm_lddqu_si128((__m128i *) (weight + x));
+          }
+        }
+        __m128i w1 = _mm_sub_epi16(mmEight, w0);
+
+        __m128i s0tmp = _mm_unpacklo_epi16(s0, s1);
+        __m128i w0tmp = _mm_unpacklo_epi16(w0, w1);
+        s0tmp = _mm_add_epi32(_mm_madd_epi16(s0tmp, w0tmp), mmOffset);
+        s0tmp = _mm_sra_epi32(s0tmp, mmShift);
+
+        s0 = _mm_unpackhi_epi16(s0, s1);
+        w0 = _mm_unpackhi_epi16(w0, w1);
+        s0 = _mm_add_epi32(_mm_madd_epi16(s0, w0), mmOffset);
+        s0 = _mm_sra_epi32(s0, mmShift);
+
+        s0 = _mm_packs_epi32(s0tmp, s0);
+        s0 = _mm_min_epi16(mmMax, _mm_max_epi16(s0, mmMin));
+        _mm_storeu_si128((__m128i *) (dst + x), s0);
+      }
+      dst += strideDst;
+      src0 += strideSrc0;
+      src1 += strideSrc1;
+      weight += stepY;
+    }
+  }
+}
+#endif
 
 template <X86_VEXT vext>
 void InterpolationFilter::_initInterpolationFilterX86()
@@ -1489,7 +1711,11 @@ void InterpolationFilter::_initInterpolationFilterX86()
   m_filterCopy[1][0]   = simdFilterCopy<vext, true, false>;
   m_filterCopy[1][1]   = simdFilterCopy<vext, true, true>;
 
+#if !JVET_Q0806
   m_weightedTriangleBlk = xWeightedTriangleBlk_SSE<vext>;
+#else
+  m_weightedGeoBlk = xWeightedGeoBlk_SSE<vext>;
+#endif
 }
 
 template void InterpolationFilter::_initInterpolationFilterX86<SIMDX86>();
diff --git a/source/Lib/CommonLib/x86/RdCostX86.h b/source/Lib/CommonLib/x86/RdCostX86.h
index b5e3288be1949c3540b222b59ef011d53d84b32a..b11df9504448ceb4db9fd248851b1c38ff52736d 100644
--- a/source/Lib/CommonLib/x86/RdCostX86.h
+++ b/source/Lib/CommonLib/x86/RdCostX86.h
@@ -1973,6 +1973,97 @@ static uint32_t xCalcHAD8x16_AVX2( const Pel* piOrg, const Pel* piCur, const int
   return (sad);
 }
 
+#if JVET_Q0806
+template< X86_VEXT vext >
+Distortion RdCost::xGetSADwMask_SIMD( const DistParam &rcDtParam )
+{
+  if (rcDtParam.org.width < 4  || rcDtParam.bitDepth > 10 || rcDtParam.applyWeight)
+    return RdCost::xGetSADwMask( rcDtParam );
+
+  const short* src1   = (const short*)rcDtParam.org.buf;
+  const short* src2   = (const short*)rcDtParam.cur.buf;
+  const short* weightMask   = (const short*)rcDtParam.mask;
+  int  rows           = rcDtParam.org.height;
+  int  cols           = rcDtParam.org.width;
+  int  subShift       = rcDtParam.subShift;
+  int  subStep        = ( 1 << subShift);
+  const int strideSrc1 = rcDtParam.org.stride * subStep;
+  const int strideSrc2 = rcDtParam.cur.stride * subStep;
+  const int strideMask = rcDtParam.maskStride * subStep;
+
+  Distortion sum = 0;
+  if( vext >= AVX2 && (cols & 15 ) == 0 )
+  {
+#ifdef USE_AVX2
+    // Do for width that multiple of 16
+    __m256i vzero = _mm256_setzero_si256();
+    __m256i vsum32 = vzero;
+    for( int y = 0; y < rows; y+= subStep)
+    {
+      for( int x = 0; x < cols; x+=16 )
+      {
+        __m256i vsrc1 = _mm256_lddqu_si256( ( __m256i* )( &src1[x] ) );
+        __m256i vsrc2 = _mm256_lddqu_si256( ( __m256i* )( &src2[x] ) );
+        __m256i vmask;
+        if (rcDtParam.stepX == -1)
+        {
+          vmask = _mm256_lddqu_si256((__m256i*)((&weightMask[x]) - (x << 1) - (16 - 1)));
+          const __m256i shuffle_mask = _mm256_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+          vmask = _mm256_shuffle_epi8(vmask, shuffle_mask);
+          vmask = _mm256_permute4x64_epi64(vmask, _MM_SHUFFLE(1, 0, 3, 2));
+        }
+        else
+        {
+          vmask = _mm256_lddqu_si256((__m256i*)(&weightMask[x]));
+        }
+        vsum32 = _mm256_add_epi32( vsum32, _mm256_madd_epi16( vmask, _mm256_abs_epi16( _mm256_sub_epi16( vsrc1, vsrc2 ) ) ) );
+      }
+      src1 += strideSrc1;
+      src2 += strideSrc2;
+      weightMask += strideMask;
+    }
+    vsum32 = _mm256_hadd_epi32( vsum32, vzero );
+    vsum32 = _mm256_hadd_epi32( vsum32, vzero );
+    sum =  _mm_cvtsi128_si32( _mm256_castsi256_si128( vsum32 ) ) + _mm_cvtsi128_si32( _mm256_castsi256_si128( _mm256_permute2x128_si256( vsum32, vsum32, 0x11 ) ) );
+#endif
+  }
+  else
+  {
+    // Do with step of 8
+    __m128i vzero = _mm_setzero_si128();
+    __m128i vsum32 = vzero;
+    for( int y = 0; y < rows; y+= subStep)
+    {
+      for( int x = 0; x < cols; x+=8 )
+      {
+        __m128i vsrc1 = _mm_loadu_si128( ( const __m128i* )( &src1[x] ) );
+        __m128i vsrc2 = _mm_lddqu_si128( ( const __m128i* )( &src2[x] ) );
+        __m128i vmask;
+        if (rcDtParam.stepX == -1)
+        {
+          vmask = _mm_lddqu_si128((__m128i*)((&weightMask[x]) - (x << 1) - (8 - 1)));
+          const __m128i shuffle_mask = _mm_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
+          vmask = _mm_shuffle_epi8(vmask, shuffle_mask);
+        }
+        else
+        {
+          vmask = _mm_lddqu_si128((const __m128i*)(&weightMask[x]));
+        }
+        vsum32 = _mm_add_epi32( vsum32, _mm_madd_epi16( vmask, _mm_abs_epi16( _mm_sub_epi16( vsrc1, vsrc2 ) ) ) );
+      }
+      src1 += strideSrc1;
+      src2 += strideSrc2;
+      weightMask += strideMask;
+    }
+    vsum32 = _mm_hadd_epi32( vsum32, vzero );
+    vsum32 = _mm_hadd_epi32( vsum32, vzero );
+    sum =  _mm_cvtsi128_si32( vsum32 );
+  }
+  sum <<= subShift;
+
+  return sum >> DISTORTION_PRECISION_ADJUSTMENT(rcDtParam.bitDepth);
+}
+#endif
 
 template<X86_VEXT vext>
 Distortion RdCost::xGetHADs_SIMD( const DistParam &rcDtParam )
@@ -2150,6 +2241,10 @@ void RdCost::_initRdCostX86()
   m_afpDistortFunc[DF_HAD16N]  = RdCost::xGetHADs_SIMD<vext>;
 
   m_afpDistortFunc[DF_SAD_INTERMEDIATE_BITDEPTH] = RdCost::xGetSAD_IBD_SIMD<vext>;
+
+#if JVET_Q0806
+  m_afpDistortFunc[DF_SAD_WITH_MASK] = xGetSADwMask_SIMD<vext>;
+#endif
 }
 
 template void RdCost::_initRdCostX86<SIMDX86>();
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index b8f20a7dee8845906193124edffe83d6e396f1a1..08e21e18342c54ed0421f1443206e1c9bafec7d1 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -2165,10 +2165,20 @@ void CABACReader::merge_data( PredictionUnit& pu )
     }
 
     RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__MERGE_FLAG );
+
+#if JVET_Q0806
+    const bool ciipAvailable = pu.cs->sps->getUseCiip() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE && pu.cu->lwidth() * pu.cu->lheight() >= 64;
+    const bool geoAvailable = pu.cu->cs->slice->getSPS()->getUseGeo() && pu.cu->cs->slice->isInterB() && pu.cu->cs->picHeader->getMaxNumGeoCand() > 1
+                                                                      && pu.cu->lwidth() >= GEO_MIN_CU_SIZE && pu.cu->lheight() >= GEO_MIN_CU_SIZE
+                                                                      && pu.cu->lwidth() <= GEO_MAX_CU_SIZE && pu.cu->lheight() <= GEO_MAX_CU_SIZE
+                                                                      && pu.cu->lwidth() < 8 * pu.cu->lheight() && pu.cu->lheight() < 8 * pu.cu->lwidth();
+    if (geoAvailable || ciipAvailable)
+#else
     const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->picHeader->getMaxNumTriangleCand() > 1;
     const bool ciipAvailable = pu.cs->sps->getUseCiip() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;
     if (pu.cu->lwidth() * pu.cu->lheight() >= 64
       && (triangleAvailable || ciipAvailable))
+#endif
     {
       cu.firstPU->regularMergeFlag = m_BinDecoder.decodeBin(Ctx::RegularMergeFlag(cu.skip ? 0 : 1));
     }
@@ -2195,6 +2205,7 @@ void CABACReader::merge_data( PredictionUnit& pu )
     {
       pu.mmvdMergeFlag = false;
       pu.cu->mmvdSkip = false;
+#if !JVET_Q0806
       if (triangleAvailable && ciipAvailable)
       {
         Ciip_flag(pu);
@@ -2216,6 +2227,29 @@ void CABACReader::merge_data( PredictionUnit& pu )
       {
         pu.cu->triangle = true;
       }
+#else
+      if (geoAvailable && ciipAvailable)
+      {
+        Ciip_flag(pu);
+      }
+      else if (ciipAvailable)
+      {
+        pu.ciipFlag = true;
+      }
+      else
+      {
+        pu.ciipFlag = false;
+      }
+      if (pu.ciipFlag)
+      {
+        pu.intraDir[0] = PLANAR_IDX;
+        pu.intraDir[1] = DM_CHROMA_IDX;
+      }
+      else
+      {
+        pu.cu->geoFlag = true;
+      }
+#endif
     }
   }
   if (pu.mmvdMergeFlag || pu.cu->mmvdSkip)
@@ -2258,6 +2292,7 @@ void CABACReader::merge_idx( PredictionUnit& pu )
   int numCandminus1 = int( pu.cs->picHeader->getMaxNumMergeCand() ) - 1;
   pu.mergeIdx       = 0;
 
+#if !JVET_Q0806
   if( pu.cu->triangle )
   {
     RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__TRIANGLE_INDEX );
@@ -2295,6 +2330,40 @@ void CABACReader::merge_idx( PredictionUnit& pu )
     pu.triangleMergeIdx1 = candIdx1;
     return;
   }
+#else
+  if( pu.cu->geoFlag )
+  {
+    RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__GEO_INDEX );
+    uint32_t splitDir  = 0;
+    xReadTruncBinCode(splitDir, GEO_NUM_PARTITION_MODE);
+    pu.geoSplitDir = splitDir;
+    const int maxNumGeoCand = pu.cs->picHeader->getMaxNumGeoCand();
+    CHECK(maxNumGeoCand < 2, "Incorrect max number of geo candidates");
+    CHECK(pu.cu->lheight() > 64 || pu.cu->lwidth() > 64, "Incorrect block size of geo flag");
+    int numCandminus2 = maxNumGeoCand - 2;
+    pu.mergeIdx = 0;
+    int mergeCand0 = 0;
+    int mergeCand1 = 0;
+    if( m_BinDecoder.decodeBin( Ctx::MergeIdx() ) )
+    {
+      mergeCand0 += unary_max_eqprob(numCandminus2) + 1;
+    }
+    if (numCandminus2 > 0)
+    {
+      if (m_BinDecoder.decodeBin(Ctx::MergeIdx()))
+      {
+        mergeCand1 += unary_max_eqprob(numCandminus2 - 1) + 1;
+      }
+    }
+    mergeCand1 += mergeCand1 >= mergeCand0 ? 1 : 0;
+    pu.geoMergeIdx0 = mergeCand0;
+    pu.geoMergeIdx1 = mergeCand1;
+    DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() geo_split_dir=%d\n", splitDir );
+    DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() geo_idx0=%d\n", mergeCand0 );
+    DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() geo_idx1=%d\n", mergeCand1 );
+    return;
+  }
+#endif
 
   if (pu.cu->predMode == MODE_IBC)
   {
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 88b6a9cd3d8bbfdba72c701d9968aa716927c4d7..9298a4cb2b9b42a1ba76a63a92f0dbf92e54d191 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -644,6 +644,7 @@ void DecCu::xFillPCMBuffer(CodingUnit &cu)
 
 void DecCu::xReconInter(CodingUnit &cu)
 {
+#if !JVET_Q0806
   if( cu.triangle )
   {
     const bool    splitDir = cu.firstPU->triangleSplitDir;
@@ -653,13 +654,25 @@ void DecCu::xReconInter(CodingUnit &cu)
     PU::spanTriangleMotionInfo( *cu.firstPU, m_triangleMrgCtx, splitDir, candIdx0, candIdx1 );
   }
   else
+#else
+  if( cu.geoFlag )
+  {
+    m_pcInterPred->motionCompensationGeo( cu, m_geoMrgCtx );
+    PU::spanGeoMotionInfo( *cu.firstPU, m_geoMrgCtx, cu.firstPU->geoSplitDir, cu.firstPU->geoMergeIdx0, cu.firstPU->geoMergeIdx1 );
+  }
+  else
+#endif
   {
   m_pcIntraPred->geneIntrainterPred(cu);
 
   // inter prediction
   CHECK(CU::isIBC(cu) && cu.firstPU->ciipFlag, "IBC and Ciip cannot be used together");
   CHECK(CU::isIBC(cu) && cu.affine, "IBC and Affine cannot be used together");
+#if !JVET_Q0806
   CHECK(CU::isIBC(cu) && cu.triangle, "IBC and triangle cannot be used together");
+#else
+  CHECK(CU::isIBC(cu) && cu.geoFlag, "IBC and geo cannot be used together");
+#endif
   CHECK(CU::isIBC(cu) && cu.firstPU->mmvdMergeFlag, "IBC and MMVD cannot be used together");
   const bool luma = cu.Y().valid();
   const bool chroma = cu.Cb().valid();
@@ -899,11 +912,19 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
       else
       {
       {
+#if !JVET_Q0806
         if( pu.cu->triangle )
         {
           PU::getTriangleMergeCandidates( pu, m_triangleMrgCtx );
         }
         else
+#else
+        if( pu.cu->geoFlag )
+        {
+          PU::getGeoMergeCandidates( pu, m_geoMrgCtx );
+        }
+        else
+#endif
         {
         if( pu.cu->affine )
         {
@@ -1047,6 +1068,7 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         PU::spanMotionInfo( pu, mrgCtx );
       }
     }
+#if !JVET_Q0806
     if( !cu.triangle )
     {
       if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
@@ -1054,6 +1076,15 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         printf( "DECODER: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
       }
     }
+#else
+    if( !cu.geoFlag )
+    {
+      if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
+      {
+        printf( "DECODER: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+      }
+    }
+#endif
     if (CU::isIBC(cu))
     {
       const int cuPelX = pu.Y().x;
diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h
index 2cbb597a9b9a48a09675b02746ef44840e9384df..c6932f3e91866433cec7aacf29e3530e6b0c01ed 100644
--- a/source/Lib/DecoderLib/DecCu.h
+++ b/source/Lib/DecoderLib/DecCu.h
@@ -98,7 +98,11 @@ private:
 
   MotionInfo        m_SubPuMiBuf[(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
 
+#if !JVET_Q0806
   MergeCtx          m_triangleMrgCtx;
+#else
+  MergeCtx          m_geoMrgCtx;
+#endif
 };
 
 //! \}
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 0943115a94dc7020b4ef373a2bf64e0de35f6952..bb9bdd280916ecc936aa35be1ab73f4cb5ef21e2 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -698,7 +698,11 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS, ParameterSetManager *parameterSetMana
     READ_CODE( 2, uiCode, "pps_mvd_l1_zero_idc");              pcPPS->setPPSMvdL1ZeroIdc(uiCode);
     READ_CODE( 2, uiCode, "pps_collocated_from_l0_idc");       pcPPS->setPPSCollocatedFromL0Idc(uiCode);
     READ_UVLC( uiCode, "pps_six_minus_max_num_merge_cand_plus1"); pcPPS->setPPSSixMinusMaxNumMergeCandPlus1(uiCode);
+#if !JVET_Q0806
     READ_UVLC( uiCode, "pps_max_num_merge_cand_minus_max_num_triangle_cand_plus1");pcPPS->setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(uiCode);
+#else
+    READ_UVLC(uiCode, "pps_max_num_merge_cand_minus_max_num_gpm_cand_plus1"); pcPPS->setPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1(uiCode);
+#endif
   }
   else
   {
@@ -708,7 +712,11 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS, ParameterSetManager *parameterSetMana
     pcPPS->setPPSMvdL1ZeroIdc(0);
     pcPPS->setPPSCollocatedFromL0Idc(0);
     pcPPS->setPPSSixMinusMaxNumMergeCandPlus1(0);
+#if !JVET_Q0806
     pcPPS->setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(0);
+#else
+    pcPPS->setPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1(0);
+#endif
   }
 
 
@@ -1166,6 +1174,44 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     READ_CODE(8, uiCode, "sps_num_subpics_minus1"); pcSPS->setNumSubPics(uiCode + 1);
     for (int picIdx = 0; picIdx < pcSPS->getNumSubPics(); picIdx++)
     {
+#if JVET_Q0787_SUBPIC
+      if (pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize())
+      {
+        READ_CODE(ceilLog2((pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), uiCode, "subpic_ctu_top_left_x[ i ]");
+        pcSPS->setSubPicCtuTopLeftX(picIdx, uiCode);
+      }
+      else
+      {
+        pcSPS->setSubPicCtuTopLeftX(picIdx, 0);
+      }
+      if (pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize())
+      {
+        READ_CODE(ceilLog2((pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), uiCode, "subpic_ctu_top_left_y[ i ]");
+        pcSPS->setSubPicCtuTopLeftY(picIdx, uiCode);
+      }
+      else
+      {
+        pcSPS->setSubPicCtuTopLeftY(picIdx, 0);
+      }
+      if (pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize())
+      {
+        READ_CODE(ceilLog2((pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), uiCode, "subpic_width_minus1[ i ]");
+        pcSPS->setSubPicWidth(picIdx, uiCode + 1);
+      }
+      else
+      {
+        pcSPS->setSubPicWidth(picIdx, 1);
+      }
+      if (pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize())
+      {
+        READ_CODE(ceilLog2((pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), uiCode, "subpic_height_minus1[ i ]");
+        pcSPS->setSubPicHeight(picIdx, uiCode + 1);
+      }
+      else
+      {
+        pcSPS->setSubPicHeight(picIdx, 1);
+      }
+#else
       READ_CODE(std::max(1, ceilLog2(((pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize())))), uiCode, "subpic_ctu_top_left_x[ i ]");
       pcSPS->setSubPicCtuTopLeftX(picIdx, uiCode);
       READ_CODE(std::max(1, ceilLog2(((pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize())))), uiCode, "subpic_ctu_top_left_y[ i ]");
@@ -1174,6 +1220,7 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
       pcSPS->setSubPicWidth(picIdx, uiCode + 1);
       READ_CODE(std::max(1, ceilLog2(((pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize())))), uiCode, "subpic_height_minus1[ i ]");
       pcSPS->setSubPicHeight(picIdx, uiCode + 1);
+#endif
       READ_FLAG(uiCode, "subpic_treated_as_pic_flag[ i ]");
       pcSPS->setSubPicTreatedAsPicFlag(picIdx, uiCode);
       READ_FLAG(uiCode, "loop_filter_across_subpic_enabled_flag[ i ]");
@@ -1549,7 +1596,11 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     READ_FLAG( uiCode,  "sps_fpel_mmvd_enabled_flag" );             pcSPS->setFpelMmvdEnabledFlag ( uiCode != 0 );
   }
 
+#if !JVET_Q0806
   READ_FLAG( uiCode,    "triangle_flag" );                          pcSPS->setUseTriangle            ( uiCode != 0 );
+#else
+  READ_FLAG( uiCode,    "sps_gpm_enabled_flag" );                               pcSPS->setUseGeo                 ( uiCode != 0 );
+#endif
 
   READ_FLAG(uiCode, "sps_lmcs_enable_flag");                   pcSPS->setUseLmcs(uiCode == 1);
   READ_FLAG( uiCode, "sps_lfnst_enabled_flag" );                    pcSPS->setUseLFNST( uiCode != 0 );
@@ -2328,6 +2379,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
     picHeader->setDisProfFlag(0);
   }
 
+#if !JVET_Q0806
   // triangle merge candidate list size
   if (sps->getUseTriangle() && picHeader->getMaxNumMergeCand() >= 2)
   {
@@ -2346,6 +2398,26 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
   {
     picHeader->setMaxNumTriangleCand(0);
   }
+#else
+  // geometric merge candidate list size
+  if (sps->getUseGeo() && picHeader->getMaxNumMergeCand() >= 2)
+  {
+    if (!pps->getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1())
+    {
+      READ_UVLC(uiCode, "pic_max_num_merge_cand_minus_max_num_gpm_cand");
+    }
+    else
+    {
+      uiCode = pps->getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1() - 1;
+    }
+    CHECK(picHeader->getMaxNumMergeCand() < uiCode, "Incorrrect max number of gpm candidates!");
+    picHeader->setMaxNumGeoCand((uint32_t)(picHeader->getMaxNumMergeCand() - uiCode));
+  }
+  else
+  {
+    picHeader->setMaxNumGeoCand(0);
+  }
+#endif
 
   // ibc merge candidate list size
   if (sps->getIBCFlag())
@@ -3428,7 +3500,11 @@ void HLSyntaxReader::parseConstraintInfo(ConstraintInfo *cinfo)
   READ_FLAG(symbol, "no_ibc_constraint_flag");                     cinfo->setNoIbcConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol, "no_ciip_constraint_flag");                    cinfo->setNoCiipConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol, "no_fpel_mmvd_constraint_flag");               cinfo->setNoFPelMmvdConstraintFlag(symbol > 0 ? true : false);
+#if !JVET_Q0806
   READ_FLAG(symbol, "no_triangle_constraint_flag");                cinfo->setNoTriangleConstraintFlag(symbol > 0 ? true : false);
+#else
+  READ_FLAG(symbol, "no_gpm_constraint_flag");                     cinfo->setNoGeoConstraintFlag(symbol > 0 ? true : false);
+#endif
   READ_FLAG(symbol, "no_ladf_constraint_flag");                    cinfo->setNoLadfConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol, "no_transform_skip_constraint_flag");          cinfo->setNoTransformSkipConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol, "no_bdpcm_constraint_flag");                   cinfo->setNoBDPCMConstraintFlag(symbol > 0 ? true : false);
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 4044ba80eece7c7925d054bb2c5bf9381686fc5a..441fe0465d068ff195c43326be4498f5a99fe5fb 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -1884,10 +1884,19 @@ void CABACWriter::merge_data(const PredictionUnit& pu)
     merge_idx(pu);
     return;
   }
+#if JVET_Q0806
+  const bool ciipAvailable = pu.cs->sps->getUseCiip() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE && pu.cu->lwidth() * pu.cu->lheight() >= 64;
+  const bool geoAvailable = pu.cu->cs->slice->getSPS()->getUseGeo() && pu.cu->cs->slice->isInterB() && pu.cu->cs->picHeader->getMaxNumGeoCand() > 1
+                                                                    && pu.cu->lwidth() >= GEO_MIN_CU_SIZE && pu.cu->lheight() >= GEO_MIN_CU_SIZE
+                                                                    && pu.cu->lwidth() <= GEO_MAX_CU_SIZE && pu.cu->lheight() <= GEO_MAX_CU_SIZE
+                                                                    && pu.cu->lwidth() < 8 * pu.cu->lheight() && pu.cu->lheight() < 8 * pu.cu->lwidth();
+  if (geoAvailable || ciipAvailable)
+#else
   const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->picHeader->getMaxNumTriangleCand() > 1;
   const bool ciipAvailable = pu.cs->sps->getUseCiip() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;
   if (pu.cu->lwidth() * pu.cu->lheight() >= 64
     && (triangleAvailable || ciipAvailable))
+#endif
   {
     m_BinEncoder.encodeBin(pu.regularMergeFlag, Ctx::RegularMergeFlag(pu.cu->skip ? 0 : 1));
   }
@@ -1909,10 +1918,17 @@ void CABACWriter::merge_data(const PredictionUnit& pu)
   }
   else
   {
+#if !JVET_Q0806
     if (triangleAvailable && ciipAvailable)
     {
       Ciip_flag(pu);
     }
+#else
+    if (geoAvailable && ciipAvailable)
+    {
+      Ciip_flag(pu);
+    }
+#endif
     merge_idx(pu);
   }
 }
@@ -2013,6 +2029,7 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
   }
   else
   {
+#if !JVET_Q0806
     if( pu.cu->triangle )
     {
       bool    splitDir = pu.triangleSplitDir;
@@ -2056,6 +2073,38 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
       encodeOneIdx(candIdx1, maxNumTriangleCand - 2);
       return;
     }
+#else
+    if( pu.cu->geoFlag )
+    {
+      uint8_t splitDir = pu.geoSplitDir;
+      uint8_t candIdx0 = pu.geoMergeIdx0;
+      uint8_t candIdx1 = pu.geoMergeIdx1;
+      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() geo_split_dir=%d\n", splitDir );
+      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() geo_idx0=%d\n", candIdx0 );
+      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() geo_idx1=%d\n", candIdx1 );
+      xWriteTruncBinCode(splitDir, GEO_NUM_PARTITION_MODE);
+      candIdx1 -= candIdx1 < candIdx0 ? 0 : 1;
+      const int maxNumGeoCand = pu.cs->picHeader->getMaxNumGeoCand();
+      CHECK(maxNumGeoCand < 2, "Incorrect max number of geo candidates");
+      CHECK(candIdx0 >= maxNumGeoCand, "Incorrect candIdx0");
+      CHECK(candIdx1 >= maxNumGeoCand, "Incorrect candIdx1");
+      int numCandminus2 = maxNumGeoCand - 2;
+      m_BinEncoder.encodeBin( candIdx0 == 0 ? 0 : 1, Ctx::MergeIdx() );
+      if( candIdx0 > 0 )
+      {
+        unary_max_eqprob(candIdx0 - 1, numCandminus2);
+      }
+      if (numCandminus2 > 0)
+      {
+        m_BinEncoder.encodeBin(candIdx1 == 0 ? 0 : 1, Ctx::MergeIdx());
+        if (candIdx1 > 0)
+        {
+          unary_max_eqprob(candIdx1 - 1, numCandminus2 - 1);
+        }
+      }
+      return;
+    }
+#endif
     int numCandminus1;
     if (pu.cu->predMode == MODE_IBC)
       numCandminus1 = int(pu.cs->picHeader->getMaxNumIBCMergeCand()) - 1;
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 7f8afbe6211b77ed354c2630b7eeee84d6ceb944..0e30d01bbb8b04bf96ba2af1777c4d45aa2537bd 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -188,7 +188,11 @@ protected:
   bool      m_noIbcConstraintFlag;
   bool      m_bNoCiipConstraintFlag;
   bool      m_noFPelMmvdConstraintFlag;
+#if !JVET_Q0806
   bool      m_bNoTriangleConstraintFlag;
+#else
+  bool      m_noGeoConstraintFlag;
+#endif
   bool      m_bNoLadfConstraintFlag;
   bool      m_noTransformSkipConstraintFlag;
   bool      m_noBDPCMConstraintFlag;
@@ -304,7 +308,11 @@ protected:
 #endif
 
   bool      m_ciip;
+#if !JVET_Q0806
   bool      m_Triangle;
+#else
+  bool      m_Geo;
+#endif
   bool      m_allowDisFracMMVD;
   bool      m_AffineAmvr;
   bool      m_HashME;
@@ -603,7 +611,11 @@ protected:
 #endif
   uint32_t      m_maxNumMergeCand;                    ///< Maximum number of merge candidates
   uint32_t      m_maxNumAffineMergeCand;              ///< Maximum number of affine merge candidates
+#if !JVET_Q0806
   uint32_t      m_maxNumTriangleCand;
+#else
+  uint32_t      m_maxNumGeoCand;
+#endif
   uint32_t      m_maxNumIBCMergeCand;                 ///< Max number of IBC merge candidates
   ScalingListMode m_useScalingListId;             ///< Using quantization matrix i.e. 0=off, 1=default, 2=file.
   std::string m_scalingListFileName;              ///< quantization matrix file name
@@ -620,7 +632,11 @@ protected:
   int       m_PPSMvdL1ZeroIdc;
   int       m_PPSCollocatedFromL0Idc;
   uint32_t  m_PPSSixMinusMaxNumMergeCandPlus1;
+#if !JVET_Q0806
   uint32_t  m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1;
+#else
+  uint32_t  m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1;
+#endif
   bool      m_DepQuantEnabledFlag;
   bool      m_SignDataHidingEnabledFlag;
   bool      m_RCEnableRateControl;
@@ -779,8 +795,13 @@ public:
   void      setNoCiipConstraintFlag(bool bVal) { m_bNoCiipConstraintFlag = bVal; }
   bool      getNoFPelMmvdConstraintFlag() const { return m_noFPelMmvdConstraintFlag; }
   void      setNoFPelMmvdConstraintFlag(bool bVal) { m_noFPelMmvdConstraintFlag = bVal; }
+#if !JVET_Q0806
   bool      getNoTriangleConstraintFlag() const { return m_bNoTriangleConstraintFlag; }
   void      setNoTriangleConstraintFlag(bool bVal) { m_bNoTriangleConstraintFlag = bVal; }
+#else
+  bool      getNoGeoConstraintFlag() const { return m_noGeoConstraintFlag; }
+  void      setNoGeoConstraintFlag(bool bVal) { m_noGeoConstraintFlag = bVal; }
+#endif
   bool      getNoLadfConstraintFlag() const { return m_bNoLadfConstraintFlag; }
   void      setNoLadfConstraintFlag(bool bVal) { m_bNoLadfConstraintFlag = bVal; }
   bool      getNoTransformSkipConstraintFlag() const { return m_noTransformSkipConstraintFlag; }
@@ -988,8 +1009,13 @@ public:
 
   void      setUseCiip                   ( bool b )       { m_ciip = b; }
   bool      getUseCiip                   ()         const { return m_ciip; }
+#if !JVET_Q0806
   void      setUseTriangle                  ( bool b )       { m_Triangle = b; }
   bool      getUseTriangle                  ()         const { return m_Triangle; }
+#else
+  void      setUseGeo                       ( bool b )       { m_Geo = b; }
+  bool      getUseGeo                       ()         const { return m_Geo; }
+#endif
   void      setAllowDisFracMMVD             ( bool b )       { m_allowDisFracMMVD = b;    }
   bool      getAllowDisFracMMVD             ()         const { return m_allowDisFracMMVD; }
   void      setUseHashME                    ( bool b )       { m_HashME = b; }
@@ -1612,8 +1638,13 @@ public:
   uint32_t         getMaxNumMergeCand                ()                  { return m_maxNumMergeCand;   }
   void         setMaxNumAffineMergeCand          ( uint32_t u )      { m_maxNumAffineMergeCand = u;    }
   uint32_t     getMaxNumAffineMergeCand          ()                  { return m_maxNumAffineMergeCand; }
+#if !JVET_Q0806
   void         setMaxNumTriangleCand             ( uint32_t u )      { m_maxNumTriangleCand = u;    }
   uint32_t     getMaxNumTriangleCand             ()                  { return m_maxNumTriangleCand; }
+#else
+  void         setMaxNumGeoCand                  ( uint32_t u )      { m_maxNumGeoCand = u;    }
+  uint32_t     getMaxNumGeoCand                  ()                  { return m_maxNumGeoCand; }
+#endif
   void         setMaxNumIBCMergeCand             ( uint32_t u )      { m_maxNumIBCMergeCand = u; }
   uint32_t     getMaxNumIBCMergeCand             ()                  { return m_maxNumIBCMergeCand; }
   void         setUseScalingListId    ( ScalingListMode u )          { m_useScalingListId       = u;   }
@@ -1646,8 +1677,13 @@ public:
   int          getPPSCollocatedFromL0Idc ()                          { return m_PPSCollocatedFromL0Idc; }
   void         setPPSSixMinusMaxNumMergeCandPlus1 ( uint32_t u )     { m_PPSSixMinusMaxNumMergeCandPlus1 = u; }
   uint32_t     getPPSSixMinusMaxNumMergeCandPlus1 ()                 { return m_PPSSixMinusMaxNumMergeCandPlus1; }
+#if !JVET_Q0806
   void         setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 ( uint32_t u ) { m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 = u; }
   uint32_t     getPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1 ()  { return m_PPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1; }
+#else
+  void         setPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 ( uint32_t u ) { m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 = u; }
+  uint32_t     getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1 ()       { return m_PPSMaxNumMergeCandMinusMaxNumGeoCandPlus1; }
+#endif
   WeightedPredictionMethod getWeightedPredictionMethod() const       { return m_weightedPredictionMethod; }
   void         setWeightedPredictionMethod( WeightedPredictionMethod m ) { m_weightedPredictionMethod = m; }
   void         setDepQuantEnabledFlag( bool b )                      { m_DepQuantEnabledFlag = b;    }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index e33e976488c070a10814dff2fac039994f5890c7..011ce09d3ac128435543ec07d31b289d850b3e90 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -59,6 +59,7 @@
 //! \{
 
 // ====================================================================================================================
+#if !JVET_Q0806
 EncCu::EncCu() : m_triangleModeTest
 {
   TriangleMotionInfo( 0, 1, 0 ), TriangleMotionInfo( 1, 0, 1 ), TriangleMotionInfo( 1, 0, 2 ), TriangleMotionInfo( 0, 0, 1 ), TriangleMotionInfo( 0, 2, 0 ),
@@ -71,6 +72,18 @@ EncCu::EncCu() : m_triangleModeTest
   TriangleMotionInfo( 0, 3, 1 ), TriangleMotionInfo( 0, 2, 4 ), TriangleMotionInfo( 1, 2, 4 ), TriangleMotionInfo( 0, 4, 2 ), TriangleMotionInfo( 0, 3, 4 ),
 }
 {}
+#else
+EncCu::EncCu() : m_GeoModeTest
+{
+  GeoMotionInfo(0, 1), GeoMotionInfo(1, 0),GeoMotionInfo(0, 2), GeoMotionInfo(1, 2), GeoMotionInfo(2, 0),
+  GeoMotionInfo(2, 1), GeoMotionInfo(0, 3),GeoMotionInfo(1, 3), GeoMotionInfo(2, 3), GeoMotionInfo(3, 0),
+  GeoMotionInfo(3, 1), GeoMotionInfo(3, 2),GeoMotionInfo(0, 4), GeoMotionInfo(1, 4), GeoMotionInfo(2, 4),
+  GeoMotionInfo(3, 4), GeoMotionInfo(4, 0),GeoMotionInfo(4, 1), GeoMotionInfo(4, 2), GeoMotionInfo(4, 3),
+  GeoMotionInfo(0, 5), GeoMotionInfo(1, 5),GeoMotionInfo(2, 5), GeoMotionInfo(3, 5), GeoMotionInfo(4, 5),
+  GeoMotionInfo(5, 0), GeoMotionInfo(5, 1),GeoMotionInfo(5, 2), GeoMotionInfo(5, 3), GeoMotionInfo(5, 4)
+}
+{}
+#endif
 
 void EncCu::create( EncCfg* encCfg )
 {
@@ -138,6 +151,7 @@ void EncCu::create( EncCfg* encCfg )
     m_acRealMergeBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight));
     m_acMergeTmpBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight));
   }
+#if !JVET_Q0806
   const unsigned maxNumTriangleCand = encCfg->getMaxNumTriangleCand();
   for (unsigned i = 0; i < maxNumTriangleCand; i++)
   {
@@ -174,6 +188,12 @@ void EncCu::create( EncCfg* encCfg )
   {
     m_acTriangleWeightedBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) );
   }
+#else
+  for( unsigned ui = 0; ui < GEO_MAX_TRY_WEIGHTED_SAD; ui++ )
+  {
+    m_acGeoWeightedBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) );
+  }
+#endif
 
   m_CtxBuffer.resize( maxDepth );
   m_CurrCtx = 0;
@@ -237,10 +257,17 @@ void EncCu::destroy()
     m_acRealMergeBuffer[ui].destroy();
     m_acMergeTmpBuffer[ui].destroy();
   }
+#if !JVET_Q0806
   for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_CANDS; ui++ )
   {
     m_acTriangleWeightedBuffer[ui].destroy();
   }
+#else
+  for (unsigned ui = 0; ui < GEO_MAX_TRY_WEIGHTED_SAD; ui++)
+  {
+    m_acGeoWeightedBuffer[ui].destroy();
+  }
+#endif
 }
 
 
@@ -270,6 +297,10 @@ void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) )
   m_dataId             = tId;
 #endif
   m_pcLoopFilter       = pcEncLib->getLoopFilter();
+#if JVET_Q0806
+  m_GeoCostList.init(GEO_NUM_PARTITION_MODE, m_pcEncCfg->getMaxNumGeoCand());
+  m_AFFBestSATDCost = MAX_DOUBLE;
+#endif
 
   DecCu::init( m_pcTrQuant, m_pcIntraSearch, m_pcInterSearch );
 
@@ -790,10 +821,17 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
       if (cu)
       cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip;
     }
+#if !JVET_Q0806
     else if( currTestMode.type == ETM_MERGE_TRIANGLE )
     {
       xCheckRDCostMergeTriangle2Nx2N( tempCS, bestCS, partitioner, currTestMode );
     }
+#else
+    else if( currTestMode.type == ETM_MERGE_GEO )
+    {
+      xCheckRDCostMergeGeo2Nx2N( tempCS, bestCS, partitioner, currTestMode );
+    }
+#endif
     else if( currTestMode.type == ETM_INTRA )
     {
       if (slice.getSPS()->getUseColorTrans() && !CS::isDualITree(*tempCS))
@@ -2394,7 +2432,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       cu.tileIdx          = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
       cu.skip             = false;
       cu.mmvdSkip = false;
+#if !JVET_Q0806
       cu.triangle         = false;
+#else
+      cu.geoFlag          = false;
+#endif
     //cu.affine
       cu.predMode         = MODE_INTER;
     //cu.LICFlag
@@ -2653,7 +2695,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       cu.tileIdx          = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
       cu.skip             = false;
       cu.mmvdSkip = false;
+#if !JVET_Q0806
       cu.triangle         = false;
+#else
+      cu.geoFlag          = false;
+#endif
     //cu.affine
       cu.predMode         = MODE_INTER;
     //cu.LICFlag
@@ -2815,6 +2861,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
   }
 }
 
+#if !JVET_Q0806
 void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
 {
   const Slice &slice = *tempCS->slice;
@@ -3036,6 +3083,287 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
     xCalDebCost( *bestCS, partitioner );
   }
 }
+#else
+void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode)
+{
+  const Slice &slice = *tempCS->slice;
+  CHECK(slice.getSliceType() == I_SLICE, "Merge modes not available for I-slices");
+
+  tempCS->initStructData(encTestMode.qp);
+
+  MergeCtx mergeCtx;
+  const SPS &sps = *tempCS->sps;
+
+  if (sps.getSBTMVPEnabledFlag())
+  {
+    Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
+    mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+  }
+
+  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;
+  cu.BcwIdx = BCW_DEFAULT;
+  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::getGeoMergeCandidates(pu, mergeCtx);
+
+  GeoComboCostList comboList;
+  int bitsCandTB = floorLog2(GEO_NUM_PARTITION_MODE);
+  PelUnitBuf geoBuffer[MRG_MAX_NUM_CANDS];
+  PelUnitBuf geoTempBuf[MRG_MAX_NUM_CANDS];
+  PelUnitBuf geoCombinations[GEO_MAX_TRY_WEIGHTED_SAD];
+  DistParam distParam;
+
+  const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
+  const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda();
+
+  uint8_t maxNumMergeCandidates = cu.cs->picHeader->getMaxNumGeoCand();
+  DistParam distParamWholeBlk;
+  m_pcRdCost->setDistParam(distParamWholeBlk, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y().buf, m_acMergeBuffer[0].Y().stride, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+  Distortion bestWholeBlkSad = MAX_UINT64;
+  double bestWholeBlkCost = MAX_DOUBLE;
+  Distortion *sadWholeBlk;
+  sadWholeBlk = new Distortion[maxNumMergeCandidates];
+  int *pocMrg;
+  Mv *MrgMv;
+  bool *isSkipThisCand;
+  pocMrg = new int[maxNumMergeCandidates];
+  MrgMv = new Mv[maxNumMergeCandidates];
+  isSkipThisCand = new bool[maxNumMergeCandidates];
+  for (int i = 0; i < maxNumMergeCandidates; i++)
+    isSkipThisCand[i] = false;
+  for (uint8_t mergeCand = 0; mergeCand < maxNumMergeCandidates; mergeCand++)
+  {
+    geoBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
+    mergeCtx.setMergeInfo(pu, mergeCand);
+    int MrgList = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx == -1 ? 1 : 0;
+    RefPicList MrgeRefPicList = (MrgList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
+    int MrgrefIdx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + MrgList].refIdx;
+    pocMrg[mergeCand] = tempCS->slice->getRefPic(MrgeRefPicList, MrgrefIdx)->getPOC();
+    MrgMv[mergeCand] = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + MrgList].mv;
+    if (mergeCand)
+    {
+      for (int i = 0; i < mergeCand; i++)
+      {
+        if (pocMrg[mergeCand] == pocMrg[i] && MrgMv[mergeCand] == MrgMv[i])
+        {
+          isSkipThisCand[mergeCand] = true;
+          break;
+        }
+      }
+    }
+    PU::spanMotionInfo(pu, mergeCtx);
+    if (m_pcEncCfg->getMCTSEncConstraint() && (!(MCTSHelper::checkMvBufferForMCTSConstraint(pu))))
+    {
+      tempCS->initStructData(encTestMode.qp);
+      return;
+    }
+    m_pcInterSearch->motionCompensation(pu, geoBuffer[mergeCand]);
+    geoTempBuf[mergeCand] = m_acMergeTmpBuffer[mergeCand].getBuf(localUnitArea);
+    geoTempBuf[mergeCand].Y().copyFrom(geoBuffer[mergeCand].Y());
+    geoTempBuf[mergeCand].Y().roundToOutputBitdepth(geoTempBuf[mergeCand].Y(), cu.slice->clpRng(COMPONENT_Y));
+    distParamWholeBlk.cur.buf = geoTempBuf[mergeCand].Y().buf;
+    distParamWholeBlk.cur.stride = geoTempBuf[mergeCand].Y().stride;
+    sadWholeBlk[mergeCand] = distParamWholeBlk.distFunc(distParamWholeBlk);
+    if (sadWholeBlk[mergeCand] < bestWholeBlkSad)
+    {
+      bestWholeBlkSad = sadWholeBlk[mergeCand];
+      int bitsCand = mergeCand + 1;
+      bestWholeBlkCost = (double)bestWholeBlkSad + (double)bitsCand * sqrtLambdaForFirstPass;
+    }
+  }
+  bool isGeo = true;
+  for (uint8_t mergeCand = 1; mergeCand < maxNumMergeCandidates; mergeCand++)
+  {
+    isGeo &= isSkipThisCand[mergeCand];
+  }
+  if (isGeo)
+  {
+    return;
+  }
+
+  int wIdx = floorLog2(cu.lwidth()) - GEO_MIN_CU_LOG2;
+  int hIdx = floorLog2(cu.lheight()) - GEO_MIN_CU_LOG2;
+  for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
+  {
+    int maskStride = 0, maskStride2 = 0;
+    int stepX = 1;
+    Pel* SADmask;
+    int16_t angle = g_GeoParams[splitDir][0];
+    if (g_angle2mirror[angle] == 2)
+    {
+      maskStride = -GEO_WEIGHT_MASK_SIZE;
+      maskStride2 = -(int)cu.lwidth();
+      SADmask = &g_globalGeoEncSADmask[g_angle2mask[g_GeoParams[splitDir][0]]][(GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][1]) * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+    }
+    else if (g_angle2mirror[angle] == 1)
+    {
+      stepX = -1;
+      maskStride2 = cu.lwidth();
+      maskStride = GEO_WEIGHT_MASK_SIZE;
+      SADmask = &g_globalGeoEncSADmask[g_angle2mask[g_GeoParams[splitDir][0]]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + (GEO_WEIGHT_MASK_SIZE - 1 - g_weightOffset[splitDir][hIdx][wIdx][0])];
+    }
+    else
+    {
+      maskStride = GEO_WEIGHT_MASK_SIZE;
+      maskStride2 = -(int)cu.lwidth();
+      SADmask = &g_globalGeoEncSADmask[g_angle2mask[g_GeoParams[splitDir][0]]][g_weightOffset[splitDir][hIdx][wIdx][1] * GEO_WEIGHT_MASK_SIZE + g_weightOffset[splitDir][hIdx][wIdx][0]];
+    }
+    Distortion sadSmall = 0, sadLarge = 0;
+    for (uint8_t mergeCand = 0; mergeCand < maxNumMergeCandidates; mergeCand++)
+    {
+      int bitsCand = mergeCand + 1;
+
+      m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), geoTempBuf[mergeCand].Y().buf, geoTempBuf[mergeCand].Y().stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y);
+      sadLarge = distParam.distFunc(distParam);
+      m_GeoCostList.insert(splitDir, 0, mergeCand, (double)sadLarge + (double)bitsCand * sqrtLambdaForFirstPass);
+      sadSmall = sadWholeBlk[mergeCand] - sadLarge;
+      m_GeoCostList.insert(splitDir, 1, mergeCand, (double)sadSmall + (double)bitsCand * sqrtLambdaForFirstPass);
+    }
+  }
+  delete[] sadWholeBlk;
+  delete[] pocMrg;
+  delete[] MrgMv;
+  delete[] isSkipThisCand;
+
+  for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
+  {
+    for (int GeoMotionIdx = 0; GeoMotionIdx < maxNumMergeCandidates * (maxNumMergeCandidates - 1); GeoMotionIdx++)
+    {
+      unsigned int mergeCand0 = m_GeoModeTest[GeoMotionIdx].m_candIdx0;
+      unsigned int mergeCand1 = m_GeoModeTest[GeoMotionIdx].m_candIdx1;
+      double tempCost = m_GeoCostList.singleDistList[0][splitDir][mergeCand0].cost + m_GeoCostList.singleDistList[1][splitDir][mergeCand1].cost;
+      if (tempCost > bestWholeBlkCost)
+        continue;
+      tempCost = tempCost + (double)bitsCandTB * sqrtLambdaForFirstPass;
+      comboList.list.push_back(GeoMergeCombo(splitDir, mergeCand0, mergeCand1, tempCost));
+    }
+  }
+  if (comboList.list.empty())
+    return;
+  comboList.sortByCost();
+  bool geocandHasNoResidual[GEO_MAX_TRY_WEIGHTED_SAD];
+  for (int mergeCand = 0; mergeCand < GEO_MAX_TRY_WEIGHTED_SAD; mergeCand++)
+  {
+    geocandHasNoResidual[mergeCand] = false;
+  }
+  bool bestIsSkip = false;
+  int geoNumCobo = (int)comboList.list.size();
+  static_vector<uint8_t, GEO_MAX_TRY_WEIGHTED_SAD> geoRdModeList;
+  static_vector<double, GEO_MAX_TRY_WEIGHTED_SAD> geocandCostList;
+
+  DistParam distParamSAD2;
+  const bool useHadamard = !tempCS->slice->getDisableSATDForRD();
+  m_pcRdCost->setDistParam(distParamSAD2, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, useHadamard);
+  int geoNumMrgSATDCand = min(GEO_MAX_TRY_WEIGHTED_SATD, geoNumCobo);
+
+  for (uint8_t candidateIdx = 0; candidateIdx < min(geoNumCobo, GEO_MAX_TRY_WEIGHTED_SAD); candidateIdx++)
+  {
+    int splitDir = comboList.list[candidateIdx].splitDir;
+    int mergeCand0 = comboList.list[candidateIdx].mergeIdx0;
+    int mergeCand1 = comboList.list[candidateIdx].mergeIdx1;
+
+    geoCombinations[candidateIdx] = m_acGeoWeightedBuffer[candidateIdx].getBuf(localUnitArea);
+    m_pcInterSearch->weightedGeoBlk(pu, splitDir, CHANNEL_TYPE_LUMA, geoCombinations[candidateIdx], geoBuffer[mergeCand0], geoBuffer[mergeCand1]);
+    distParamSAD2.cur = geoCombinations[candidateIdx].Y();
+    Distortion sad = distParamSAD2.distFunc(distParamSAD2);
+    int mvBits = 2;
+    mergeCand1 -= mergeCand1 < mergeCand0 ? 0 : 1;
+    mvBits += mergeCand0;
+    mvBits += mergeCand1;
+    double updateCost = (double)sad + (double)(bitsCandTB + mvBits) * sqrtLambdaForFirstPass;
+    comboList.list[candidateIdx].cost = updateCost;
+    updateCandList(candidateIdx, updateCost, geoRdModeList, geocandCostList, geoNumMrgSATDCand);
+  }
+  for (uint8_t i = 0; i < geoNumMrgSATDCand; i++)
+  {
+    if (geocandCostList[i] > MRG_FAST_RATIO * geocandCostList[0] || geocandCostList[i] > getMergeBestSATDCost() || geocandCostList[i] > getAFFBestSATDCost())
+    {
+      geoNumMrgSATDCand = i;
+      break;
+    }
+  }
+  for (uint8_t i = 0; i < geoNumMrgSATDCand && isChromaEnabled(pu.chromaFormat); i++)
+  {
+    uint8_t candidateIdx = geoRdModeList[i];
+    int splitDir = comboList.list[candidateIdx].splitDir;
+    int mergeCand0 = comboList.list[candidateIdx].mergeIdx0;
+    int mergeCand1 = comboList.list[candidateIdx].mergeIdx1;
+    geoCombinations[candidateIdx] = m_acGeoWeightedBuffer[candidateIdx].getBuf(localUnitArea);
+    m_pcInterSearch->weightedGeoBlk(pu, splitDir, CHANNEL_TYPE_CHROMA, geoCombinations[candidateIdx], geoBuffer[mergeCand0], geoBuffer[mergeCand1]);
+  }
+
+  m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
+  tempCS->initStructData(encTestMode.qp);
+  uint8_t iteration;
+  uint8_t iterationBegin = 0;
+  iteration = 2;
+  for (uint8_t noResidualPass = iterationBegin; noResidualPass < iteration; ++noResidualPass)
+  {
+    for (uint8_t mrgHADIdx = 0; mrgHADIdx < geoNumMrgSATDCand; mrgHADIdx++)
+    {
+      uint8_t candidateIdx = geoRdModeList[mrgHADIdx];
+      if (((noResidualPass != 0) && geocandHasNoResidual[candidateIdx])
+        || ((noResidualPass == 0) && bestIsSkip))
+      {
+        continue;
+      }
+      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;
+      cu.BcwIdx = BCW_DEFAULT;
+      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 = comboList.list[candidateIdx].splitDir;
+      pu.geoMergeIdx0 = comboList.list[candidateIdx].mergeIdx0;
+      pu.geoMergeIdx1 = comboList.list[candidateIdx].mergeIdx1;
+      pu.mmvdMergeFlag = false;
+      pu.mmvdMergeIdx = MAX_UINT;
+
+      PU::spanGeoMotionInfo(pu, mergeCtx, pu.geoSplitDir, pu.geoMergeIdx0, pu.geoMergeIdx1);
+      tempCS->getPredBuf().copyFrom(geoCombinations[candidateIdx]);
+
+      xEncodeInterResidual(tempCS, bestCS, pm, encTestMode, noResidualPass, (noResidualPass == 0 ? &geocandHasNoResidual[candidateIdx] : NULL));
+
+      if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip)
+      {
+        bestIsSkip = bestCS->getCU(pm.chType)->rootCbf == 0;
+      }
+      tempCS->initStructData(encTestMode.qp);
+    }
+  }
+  if (m_bestModeUpdated && bestCS->cost != MAX_DOUBLE)
+  {
+    xCalDebCost(*bestCS, pm);
+  }
+}
+#endif
 
 void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
 {
@@ -3058,6 +3386,10 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
   AffineMergeCtx affineMergeCtx;
   const SPS &sps = *tempCS->sps;
 
+#if JVET_Q0806
+  setAFFBestSATDCost(MAX_DOUBLE);
+#endif
+
   MergeCtx mrgCtx;
   if ( sps.getSBTMVPEnabledFlag() )
   {
@@ -3197,6 +3529,10 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
       }
 
       tempCS->initStructData( encTestMode.qp );
+#if JVET_Q0806
+      setAFFBestSATDCost(candCostList[0]);
+#endif
+
     }
     else
     {
@@ -3349,7 +3685,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     cu.mmvdSkip = false;
     pu.mmvdMergeFlag = false;
     pu.regularMergeFlag = false;
+#if !JVET_Q0806
     cu.triangle = false;
+#else
+    cu.geoFlag = false;
+#endif
     PU::getIBCMergeCandidates(pu, mergeCtx);
   }
 
@@ -3383,7 +3723,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       cu.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1;
       cu.qp = encTestMode.qp;
       cu.mmvdSkip = false;
+#if !JVET_Q0806
       cu.triangle = false;
+#else
+      cu.geoFlag = false;
+#endif
       DistParam distParam;
       const bool bUseHadamard = !cu.slice->getDisableSATDForRD();
       PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType); //tempCS->addPU(cu);
@@ -3500,7 +3844,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             cu.mmvdSkip = false;
             pu.mmvdMergeFlag = false;
             pu.regularMergeFlag = false;
+#if !JVET_Q0806
             cu.triangle = false;
+#else
+            cu.geoFlag = false;
+#endif
             mergeCtx.setMergeInfo(pu, mergeCand);
             PU::spanMotionInfo(pu, mergeCtx);
 
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 18b99b00a3d84a7117131e52522a41cfe588904d..91e22c548f69522b0dbbf969aa59974df7ff86d8 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -67,6 +67,7 @@ class EncSlice;
 // ====================================================================================================================
 
 /// CU encoder class
+#if !JVET_Q0806
 struct TriangleMotionInfo
 {
   uint8_t   m_splitDir;
@@ -76,6 +77,87 @@ struct TriangleMotionInfo
   TriangleMotionInfo ( uint8_t splitDir, uint8_t candIdx0, uint8_t candIdx1 ): m_splitDir(splitDir), m_candIdx0(candIdx0), m_candIdx1(candIdx1) { }
   TriangleMotionInfo() { m_splitDir = m_candIdx0 = m_candIdx1 = 0; }
 };
+#else
+struct GeoMergeCombo
+{
+  int splitDir;
+  int mergeIdx0;
+  int mergeIdx1;
+  double cost;
+  GeoMergeCombo() : splitDir(), mergeIdx0(-1), mergeIdx1(-1), cost(0.0) {};
+  GeoMergeCombo(int _splitDir, int _mergeIdx0, int _mergeIdx1, double _cost) : splitDir(_splitDir), mergeIdx0(_mergeIdx0), mergeIdx1(_mergeIdx1), cost(_cost) {};
+};
+struct GeoMotionInfo
+{
+  uint8_t   m_candIdx0;
+  uint8_t   m_candIdx1;
+
+  GeoMotionInfo(uint8_t candIdx0, uint8_t candIdx1) : m_candIdx0(candIdx0), m_candIdx1(candIdx1) { }
+  GeoMotionInfo() { m_candIdx0 = m_candIdx1 = 0; }
+};
+struct SmallerThanComboCost
+{
+  inline bool operator() (const GeoMergeCombo& first, const GeoMergeCombo& second)
+  {
+      return (first.cost < second.cost);
+  }
+};
+class GeoComboCostList
+{
+public:
+  GeoComboCostList() {};
+  ~GeoComboCostList() {};
+  std::vector<GeoMergeCombo> list;
+  void sortByCost() { std::sort(list.begin(), list.end(), SmallerThanComboCost()); };
+};
+struct SingleGeoMergeEntry
+{
+  int mergeIdx;
+  double cost;
+  SingleGeoMergeEntry() : mergeIdx(0), cost(MAX_DOUBLE) {};
+  SingleGeoMergeEntry(int _mergeIdx, double _cost) : mergeIdx(_mergeIdx), cost(_cost) {};
+};
+class FastGeoCostList
+{
+public:
+  FastGeoCostList() { numGeoTemplatesInitialized = 0; };
+  ~FastGeoCostList() 
+  {
+    for (int partIdx = 0; partIdx < 2; partIdx++)
+    {
+      for (int splitDir = 0; splitDir < GEO_NUM_PARTITION_MODE; splitDir++)
+      {
+        delete[] singleDistList[partIdx][splitDir];
+      }
+      delete[] singleDistList[partIdx];
+      singleDistList[partIdx] = nullptr;
+    }
+  };
+  SingleGeoMergeEntry** singleDistList[2];
+  void init(int numTemplates, int maxNumGeoCand)
+  {
+    if (numGeoTemplatesInitialized == 0 || numGeoTemplatesInitialized < numTemplates)
+    {
+      for (int partIdx = 0; partIdx < 2; partIdx++)
+      {
+        singleDistList[partIdx] = new SingleGeoMergeEntry*[numTemplates];
+        for (int splitDir = 0; splitDir < numTemplates; splitDir++)
+        {
+          singleDistList[partIdx][splitDir] = new SingleGeoMergeEntry[maxNumGeoCand];
+        }
+      }
+      numGeoTemplatesInitialized = numTemplates;
+    }
+  }
+  void insert(int geoIdx, int partIdx, int mergeIdx, double cost)
+  {
+    assert(geoIdx < numGeoTemplatesInitialized);
+    singleDistList[partIdx][geoIdx][mergeIdx] = SingleGeoMergeEntry(mergeIdx, cost);
+  }
+  int numGeoTemplatesInitialized;
+};
+#endif
+
 class EncCu
   : DecCu
 {
@@ -121,7 +203,13 @@ private:
   PelStorage            m_acMergeBuffer[MMVD_MRG_MAX_RD_BUF_NUM];
   PelStorage            m_acRealMergeBuffer[MRG_MAX_NUM_CANDS];
   PelStorage            m_acMergeTmpBuffer[MRG_MAX_NUM_CANDS];
+#if !JVET_Q0806
   PelStorage            m_acTriangleWeightedBuffer[TRIANGLE_MAX_NUM_CANDS]; // to store weighted prediction pixles
+#else
+  PelStorage            m_acGeoWeightedBuffer[GEO_MAX_TRY_WEIGHTED_SAD]; // to store weighted prediction pixles
+  FastGeoCostList       m_GeoCostList;
+  double                m_AFFBestSATDCost;
+#endif
   double                m_mergeBestSATDCost;
   MotionInfo            m_SubPuMiBuf      [( MAX_CU_SIZE * MAX_CU_SIZE ) >> ( MIN_CU_LOG2 << 1 )];
 
@@ -132,8 +220,12 @@ private:
 #endif
   int                   m_bestBcwIdx[2];
   double                m_bestBcwCost[2];
+#if !JVET_Q0806
   TriangleMotionInfo    m_triangleModeTest[TRIANGLE_MAX_NUM_CANDS];
   uint8_t               m_triangleIdxBins[2][TRIANGLE_MAX_NUM_UNI_CANDS][TRIANGLE_MAX_NUM_UNI_CANDS];
+#else
+  GeoMotionInfo         m_GeoModeTest[GEO_MAX_NUM_CANDS];
+#endif
 #if SHARP_LUMA_DELTA_QP || ENABLE_QPA_SUB_CTU
   void    updateLambda      ( Slice* slice, const int dQP,
  #if WCG_EXT && ER_CHROMA_QP_WCG_PPS
@@ -163,6 +255,10 @@ public:
 
   void   setMergeBestSATDCost(double cost) { m_mergeBestSATDCost = cost; }
   double getMergeBestSATDCost()            { return m_mergeBestSATDCost; }
+#if JVET_Q0806
+  void   setAFFBestSATDCost(double cost)   { m_AFFBestSATDCost = cost; }
+  double getAFFBestSATDCost()              { return m_AFFBestSATDCost; }
+#endif
   IbcHashMap& getIbcHashMap()              { return m_ibcHashMap;        }
   EncCfg*     getEncCfg()            const { return m_pcEncCfg;          }
 
@@ -202,7 +298,11 @@ protected:
 
   void xCheckRDCostMerge2Nx2N ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
 
+#if !JVET_Q0806
   void xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
+#else
+  void xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode);
+#endif
 
   void xEncodeInterResidual(   CodingStructure *&tempCS
                              , CodingStructure *&bestCS
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 27a672376fb4b57e853c98f1bf8341026835324b..fa644b5c06fd30fe11407c50e9e1a1ade448e27c 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1115,7 +1115,11 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
   cinfo->setNoIbcConstraintFlag(m_noIbcConstraintFlag);
   cinfo->setNoCiipConstraintFlag(m_bNoCiipConstraintFlag);
   cinfo->setNoFPelMmvdConstraintFlag(m_noFPelMmvdConstraintFlag);
+#if !JVET_Q0806
   cinfo->setNoTriangleConstraintFlag(m_bNoTriangleConstraintFlag);
+#else
+  cinfo->setNoGeoConstraintFlag(m_noGeoConstraintFlag);
+#endif
   cinfo->setNoLadfConstraintFlag(m_bNoLadfConstraintFlag);
   cinfo->setNoTransformSkipConstraintFlag(m_noTransformSkipConstraintFlag);
   cinfo->setNoBDPCMConstraintFlag(m_noBDPCMConstraintFlag);
@@ -1213,7 +1217,11 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
 #endif
 
   sps.setUseCiip            ( m_ciip );
+#if !JVET_Q0806
   sps.setUseTriangle           ( m_Triangle );
+#else
+  sps.setUseGeo                ( m_Geo );
+#endif
   sps.setUseMMVD               ( m_MMVD );
   sps.setFpelMmvdEnabledFlag   (( m_MMVD ) ? m_allowDisFracMMVD : false);
   sps.setBdofControlPresentFlag(m_BIO);
@@ -1430,7 +1438,11 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps)
   pps.setPPSMvdL1ZeroIdc(getPPSMvdL1ZeroIdc());
   pps.setPPSCollocatedFromL0Idc(getPPSCollocatedFromL0Idc());
   pps.setPPSSixMinusMaxNumMergeCandPlus1(getPPSSixMinusMaxNumMergeCandPlus1());
+#if !JVET_Q0806
   pps.setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(getPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1());
+#else
+  pps.setPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1(getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1());
+#endif
 
   pps.setNumSubPics(sps.getNumSubPics());
   pps.setSubPicIdSignallingPresentFlag(false);
@@ -1708,7 +1720,11 @@ void EncLib::xInitPicHeader(PicHeader &picHeader, const SPS &sps, const PPS &pps
   // merge list sizes
   picHeader.setMaxNumMergeCand      ( getMaxNumMergeCand()       );
   picHeader.setMaxNumAffineMergeCand( getMaxNumAffineMergeCand() );
+#if !JVET_Q0806
   picHeader.setMaxNumTriangleCand   ( getMaxNumTriangleCand()    );
+#else
+  picHeader.setMaxNumGeoCand        ( getMaxNumGeoCand()         );
+#endif
   picHeader.setMaxNumIBCMergeCand   ( getMaxNumIBCMergeCand()    );
   
   // copy partitioning constraints from SPS
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 833986d556bfcc41d0d55384bb98477efd857666..33d3edb25dde4ad88e91cc6c5756b82dda54e9f9 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -1364,10 +1364,17 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru
       // add inter modes
       if( m_pcEncCfg->getUseEarlySkipDetection() )
       {
+#if !JVET_Q0806
         if( cs.sps->getUseTriangle() && cs.slice->isInterB() )
         {
           m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_TRIANGLE, ETO_STANDARD, qp } );
         }
+#else
+        if( cs.sps->getUseGeo() && cs.slice->isInterB() )
+        {
+          m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_GEO, ETO_STANDARD, qp } );
+        }
+#endif
         m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_SKIP,  ETO_STANDARD, qp } );
         if ( cs.sps->getUseAffine() || cs.sps->getSBTMVPEnabledFlag() )
         {
@@ -1378,10 +1385,17 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru
       else
       {
         m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME,    ETO_STANDARD, qp } );
+#if !JVET_Q0806
         if( cs.sps->getUseTriangle() && cs.slice->isInterB() )
         {
           m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_TRIANGLE, ETO_STANDARD, qp } );
         }
+#else
+        if( cs.sps->getUseGeo() && cs.slice->isInterB() )
+        {
+          m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_GEO, ETO_STANDARD, qp } );
+        }
+#endif
         m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_SKIP,  ETO_STANDARD, qp } );
         if ( cs.sps->getUseAffine() || cs.sps->getSBTMVPEnabledFlag() )
         {
@@ -1419,7 +1433,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
   ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
 
   // Fast checks, partitioning depended
+#if !JVET_Q0806
   if (cuECtx.isHashPerfectMatch && encTestmode.type != ETM_MERGE_SKIP && encTestmode.type != ETM_INTER_ME && encTestmode.type != ETM_AFFINE && encTestmode.type != ETM_MERGE_TRIANGLE)
+#else
+  if (cuECtx.isHashPerfectMatch && encTestmode.type != ETM_MERGE_SKIP && encTestmode.type != ETM_INTER_ME && encTestmode.type != ETM_AFFINE && encTestmode.type != ETM_MERGE_GEO)
+#endif
   {
     return false;
   }
@@ -1640,10 +1658,20 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     {
       return false;
     }
+#if !JVET_Q0806
     if( encTestmode.type == ETM_MERGE_TRIANGLE && ( partitioner.currArea().lumaSize().area() < TRIANGLE_MIN_SIZE || relatedCU.isIntra ) )
     {
       return false;
     }
+#else
+    if( encTestmode.type == ETM_MERGE_GEO && ( partitioner.currArea().lwidth() < GEO_MIN_CU_SIZE || partitioner.currArea().lheight() < GEO_MIN_CU_SIZE  
+                                            || partitioner.currArea().lwidth() > GEO_MAX_CU_SIZE || partitioner.currArea().lheight() > GEO_MAX_CU_SIZE
+                                            || partitioner.currArea().lwidth() >= 8 * partitioner.currArea().lheight()
+                                            || partitioner.currArea().lheight() >= 8 * partitioner.currArea().lwidth() ) )
+    {
+      return false;
+    }
+#endif
     return true;
   }
   else if( isModeSplit( encTestmode ) )
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index 3ab1b298bafc255d2754a5eb69f176fec5b7918a..f2b75071dabfb5cdf9ebb21cc73bd6ba0ae26506 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -59,7 +59,11 @@ enum EncTestModeType
   ETM_MERGE_SKIP,
   ETM_INTER_ME,
   ETM_AFFINE,
+#if !JVET_Q0806
   ETM_MERGE_TRIANGLE,
+#else
+  ETM_MERGE_GEO,
+#endif
   ETM_INTRA,
   ETM_PALETTE,
   ETM_SPLIT_QT,
@@ -138,7 +142,11 @@ inline bool isModeInter( const EncTestMode& encTestmode ) // perhaps remove
   return (   encTestmode.type == ETM_INTER_ME
           || encTestmode.type == ETM_MERGE_SKIP
           || encTestmode.type == ETM_AFFINE
+#if !JVET_Q0806
           || encTestmode.type == ETM_MERGE_TRIANGLE
+#else
+          || encTestmode.type == ETM_MERGE_GEO
+#endif
           || encTestmode.type == ETM_HASH_INTER
          );
 }
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index 5ee8d0ee19ec6d5b677ef1ebf56d425d22c76f58..01aefd05cfdfc5b0cafe6142340bf9e5604b67db 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -1567,13 +1567,83 @@ void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, Compo
   derivePLTLossy(cs, partitioner, compBegin, numComp);
   reorderPLT(cs, partitioner, compBegin, numComp);
 
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  bool idxExist[MAXPLTSIZE + 1] = { false };
+#endif
   preCalcPLTIndexRD(cs, partitioner, compBegin, numComp); // Pre-calculate distortions for each pixel 
   double rdCost = MAX_DOUBLE;
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, rdCost, idxExist); // Optimize palette index map (horizontal scan)
+#else
   deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, rdCost); // Optimize palette index map (horizontal scan)
+#endif
   if ((cu.curPLTSize[compBegin] + cu.useEscape[compBegin]) > 1)
   {
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+    deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, rdCost, idxExist); // Optimize palette index map (vertical scan)
+#else
     deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, rdCost); // Optimize palette index map (vertical scan)
+#endif
+  }
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  // Remove unused palette entries
+  uint8_t newPLTSize = 0;
+  int idxMapping[MAXPLTSIZE + 1];
+  memset(idxMapping, -1, sizeof(int) * (MAXPLTSIZE + 1));
+  for (int i = 0; i < cu.curPLTSize[compBegin]; i++)
+  {
+    if (idxExist[i])
+    {
+      idxMapping[i] = newPLTSize;
+      newPLTSize++;
+    }
+  }
+  idxMapping[cu.curPLTSize[compBegin]] = cu.useEscape[compBegin]? newPLTSize: -1;
+  if (newPLTSize != cu.curPLTSize[compBegin]) // there exist unused palette entries
+  { // update palette table and reuseflag
+    Pel curPLTtmp[MAX_NUM_COMPONENT][MAXPLTSIZE];
+    int reuseFlagIdx = 0, curPLTtmpIdx = 0, reuseEntrySize = 0;
+    memset(cu.reuseflag[compBegin], false, sizeof(bool) * MAXPLTPREDSIZE);
+    for (int curIdx = 0; curIdx < cu.curPLTSize[compBegin]; curIdx++)
+    {
+      if (idxExist[curIdx])
+      {
+        for (int comp = compBegin; comp < (compBegin + numComp); comp++)
+          curPLTtmp[comp][curPLTtmpIdx] = cu.curPLT[comp][curIdx];
+
+        // Update reuse flags
+        if (curIdx < cu.reusePLTSize[compBegin])
+        {
+          bool match = false;
+          for (; reuseFlagIdx < cs.prevPLT.curPLTSize[compBegin]; reuseFlagIdx++)
+          {
+            bool matchTmp = true;
+            for (int comp = compBegin; comp < (compBegin + numComp); comp++)
+            {
+              matchTmp = matchTmp && (curPLTtmp[comp][curPLTtmpIdx] == cs.prevPLT.curPLT[comp][reuseFlagIdx]);
+            }
+            if (matchTmp)
+            {
+              match = true;
+              break;
+            }
+          }
+          if (match)
+          {
+            cu.reuseflag[compBegin][reuseFlagIdx] = true;
+            reuseEntrySize++;
+          }
+        }
+        curPLTtmpIdx++;
+      }
+    }
+    cu.reusePLTSize[compBegin] = reuseEntrySize;
+    // update palette table
+    cu.curPLTSize[compBegin] = newPLTSize;
+    for (int comp = compBegin; comp < (compBegin + numComp); comp++)
+      memcpy( cu.curPLT[comp], curPLTtmp[comp], sizeof(Pel)*cu.curPLTSize[compBegin]);
   }
+#endif
   cu.useRotation[compBegin] = m_bestScanRotationMode;
   int indexMaxSize = cu.useEscape[compBegin] ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];
   if (indexMaxSize <= 1)
@@ -1586,6 +1656,9 @@ void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, Compo
   {
     for (uint32_t x = 0; x < width; x++)
     {
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+      curPLTIdx.at(x, y) = idxMapping[curPLTIdx.at(x, y)];
+#endif
       if (curPLTIdx.at(x, y) == cu.curPLTSize[compBegin])
       {
         calcPixelPred(cs, partitioner, y, x, compBegin, numComp);
@@ -1782,7 +1855,11 @@ void IntraSearch::preCalcPLTIndexRD(CodingStructure& cs, Partitioner& partitione
   }
 }
 
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+void IntraSearch::deriveIndexMap(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dMinCost, bool* idxExist)
+#else
 void IntraSearch::deriveIndexMap(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dMinCost)
+#endif
 {
   CodingUnit    &cu = *cs.getCU(partitioner.chType);
   TransformUnit &tu = *cs.getTU(partitioner.chType);
@@ -1905,10 +1982,16 @@ void IntraSearch::deriveIndexMap(CodingStructure& cs, Partitioner& partitioner,
   {
     cu.useEscape[compBegin] = m_bestEscape;
     m_bestScanRotationMode = pltScanMode;
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+    memset(idxExist, false, sizeof(bool) * (MAXPLTSIZE + 1));
+#endif
     for (int pos = 0; pos < (width*height); pos++)
     {
       runIndex[pos] = checkIndexTable[pos];
       runType[pos] = checkRunTable[pos];
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+      idxExist[checkIndexTable[pos]] = true;
+#endif
     }
     dMinCost = sumRdCost;
   }
@@ -2072,16 +2155,32 @@ double IntraSearch::rateDistOptPLT(
       rdCost = MAX_DOUBLE;
       return rdCost;
     }
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+    rdCost += m_pcRdCost->getLambda()*(m_truncBinBits[(runIndex > refIndex) ? runIndex - 1 : runIndex][(scanPos == 0) ? (indexMaxValue + 1) : indexMaxValue] << SCALE_BITS);
+#else
     rdCost += m_pcRdCost->getLambda()*m_truncBinBits[(runIndex > refIndex) ? runIndex - 1 : runIndex][(scanPos == 0) ? (indexMaxValue + 1) : indexMaxValue];
+#endif
   }
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  rdCost += m_indexError[runIndex][m_scanOrder[scanPos].idx] * (1 << SCALE_BITS);
+#else
   rdCost += m_indexError[runIndex][m_scanOrder[scanPos].idx];
+#endif
   if (scanPos > 0)
   {
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+    rdCost += m_pcRdCost->getLambda()*( identityFlag ? (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[1]) : (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[0] ) );
+#else
     rdCost += m_pcRdCost->getLambda()*( identityFlag ? (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[1] >> SCALE_BITS) : (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[0] >> SCALE_BITS));
+#endif
   }
   if ( !identityFlag && scanPos >= width && prevRunType != PLT_RUN_COPY )
   {
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+    rdCost += m_pcRdCost->getLambda()*TypefracBits.intBits[runType];
+#else
     rdCost += m_pcRdCost->getLambda()*(TypefracBits.intBits[runType] >> SCALE_BITS);
+#endif
   }
   if (!identityFlag || scanPos == 0)
   {
@@ -2251,7 +2350,15 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner,
     }
   }
 
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  TransformUnit &tu = *cs.getTU(partitioner.chType);
+  QpParam cQP(tu, compBegin);
+  int qp = cQP.Qp(true) - 12;
+  qp = (qp < 0) ? 0 : ((qp > 56) ? 56 : qp);
+  int errorLimit = g_paletteQuant[qp];
+#else
   int errorLimit = g_paletteQuant[cu.qp];
+#endif
   uint32_t totalSize = height*width;
   SortingElement *pelList = new SortingElement[totalSize];
   SortingElement  element;
@@ -2340,6 +2447,11 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner,
   }
   const int plt_lambda_shift = (compBegin > 0) ? pcmShiftRight_C : pcmShiftRight_L;
   double    bitCost          = m_pcRdCost->getLambda() / (double) (1 << (2 * plt_lambda_shift)) * numColorBits;
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  bool   reuseflag[MAXPLTPREDSIZE] = { false };
+  int    run;
+  double reuseflagCost;
+#endif
   for (int i = 0; i < MAXPLTSIZE; i++)
   {
     if (pelListSort[i].getCnt())
@@ -2385,6 +2497,22 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner,
             }
           }
           cost *= pelListSort[i].getCnt();
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+          run = 0;
+          for (int t2 = t-1; t2 >= 0; t2--)
+          {
+            if (!reuseflag[t2])
+            {
+              run++;
+            }
+            else
+            {
+              break;
+            }
+          }
+          reuseflagCost = m_pcRdCost->getLambda() / (double)(1 << (2 * plt_lambda_shift)) * getEpExGolombNumBins(run ? run + 1 : run, 0);
+          cost += reuseflagCost;
+#endif
           if (cost < bestCost)
           {
             best = t;
@@ -2397,6 +2525,9 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner,
           {
             cu.curPLT[comp][paletteSize] = cs.prevPLT.curPLT[comp][best];
           }
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+          reuseflag[best] = true;
+#endif
         }
       }
 
diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h
index 72ccaa02148956bceded9d45694cbe2c7c58baf5..9370c143072ad7548d439be5a43bf1270c020143 100644
--- a/source/Lib/EncoderLib/IntraSearch.h
+++ b/source/Lib/EncoderLib/IntraSearch.h
@@ -453,7 +453,11 @@ protected:
   void   calcPixelPred   (      CodingStructure& cs, Partitioner& partitioner, uint32_t    yPos,      uint32_t xPos,             ComponentID compBegin, uint32_t  numComp);
   void     preCalcPLTIndexRD      (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp);
   void     calcPixelPredRD        (CodingStructure& cs, Partitioner& partitioner, Pel* orgBuf, Pel* pixelValue, Pel* recoValue, ComponentID compBegin, uint32_t numComp);
+#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX
+  void     deriveIndexMap         (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dCost, bool* idxExist);
+#else
   void     deriveIndexMap         (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dCost);
+#endif
   bool     deriveSubblockIndexMap(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, PLTScanMode pltScanMode, int minSubPos, int maxSubPos, const BinFracBits& fracBitsPltRunType, const BinFracBits* fracBitsPltIndexINDEX, const BinFracBits* fracBitsPltIndexCOPY, const double minCost, bool useRotate);
   double   rateDistOptPLT         (bool RunType, uint8_t RunIndex, bool prevRunType, uint8_t prevRunIndex, uint8_t aboveRunIndex, bool& prevCodedRunType, int& prevCodedRunPos, int scanPos, uint32_t width, int dist, int indexMaxValue, const BinFracBits* IndexfracBits, const BinFracBits& TypefracBits);
   void     initTBCTable           (int bitDepth);
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index caa3171e35b1bf5f7db95885cbd54538550d0433..19dd9cf2564fe91d3436b5a9d540459361abb036 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -427,7 +427,11 @@ void HLSWriter::codePPS( const PPS* pcPPS, const SPS* pcSPS )
     WRITE_CODE( pcPPS->getPPSMvdL1ZeroIdc(), 2,                              "pps_mvd_l1_zero_idc");
     WRITE_CODE( pcPPS->getPPSCollocatedFromL0Idc(), 2,                       "pps_collocated_from_l0_idc");
     WRITE_UVLC( pcPPS->getPPSSixMinusMaxNumMergeCandPlus1(),                 "pps_six_minus_max_num_merge_cand_plus1");
+#if !JVET_Q0806
     WRITE_UVLC( pcPPS->getPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(),  "pps_max_num_merge_cand_minus_max_num_triangle_cand_plus1");
+#else
+    WRITE_UVLC(pcPPS->getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1(), "pps_max_num_merge_cand_minus_max_num_gpm_cand_plus1");
+#endif
   }
 
 
@@ -778,10 +782,29 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
     WRITE_CODE(pcSPS->getNumSubPics() - 1, 8, "sps_num_subpics_minus1");
     for (int picIdx = 0; picIdx < pcSPS->getNumSubPics(); picIdx++)
     {
+#if JVET_Q0787_SUBPIC
+      if (pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize())
+      {
+        WRITE_CODE( pcSPS->getSubPicCtuTopLeftX(picIdx), ceilLog2(( pcSPS->getMaxPicWidthInLumaSamples()  +  pcSPS->getCTUSize() - 1)  / pcSPS->getCTUSize()), "subpic_ctu_top_left_x[ i ]"  );
+      }
+      if (pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize())
+      {
+        WRITE_CODE( pcSPS->getSubPicCtuTopLeftY(picIdx), ceilLog2(( pcSPS->getMaxPicHeightInLumaSamples() +  pcSPS->getCTUSize() - 1)  / pcSPS->getCTUSize()), "subpic_ctu_top_left_y[ i ]"  );
+      }
+      if (pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize())
+      {
+        WRITE_CODE( pcSPS->getSubPicWidth(picIdx) - 1,   ceilLog2(( pcSPS->getMaxPicWidthInLumaSamples()  +  pcSPS->getCTUSize() - 1)  / pcSPS->getCTUSize()), "subpic_width_minus1[ i ]"    );
+      }
+      if (pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize())
+      {
+        WRITE_CODE( pcSPS->getSubPicHeight(picIdx) - 1,  ceilLog2(( pcSPS->getMaxPicHeightInLumaSamples() +  pcSPS->getCTUSize() - 1)  / pcSPS->getCTUSize()), "subpic_height_minus1[ i ]"   );
+      }
+#else
       WRITE_CODE( pcSPS->getSubPicCtuTopLeftX(picIdx), std::max(1, ceilLog2((( pcSPS->getMaxPicWidthInLumaSamples()  +  pcSPS->getCTUSize() - 1)  >> floorLog2( pcSPS->getCTUSize())))), "subpic_ctu_top_left_x[ i ]"  );
       WRITE_CODE( pcSPS->getSubPicCtuTopLeftY(picIdx), std::max(1, ceilLog2((( pcSPS->getMaxPicHeightInLumaSamples() +  pcSPS->getCTUSize() - 1)  >> floorLog2( pcSPS->getCTUSize())))), "subpic_ctu_top_left_y[ i ]"  );
       WRITE_CODE( pcSPS->getSubPicWidth(picIdx) - 1,   std::max(1, ceilLog2((( pcSPS->getMaxPicWidthInLumaSamples()  +  pcSPS->getCTUSize() - 1)  >> floorLog2( pcSPS->getCTUSize())))), "subpic_width_minus1[ i ]"    );
       WRITE_CODE( pcSPS->getSubPicHeight(picIdx) - 1,  std::max(1, ceilLog2((( pcSPS->getMaxPicHeightInLumaSamples() +  pcSPS->getCTUSize() - 1)  >> floorLog2( pcSPS->getCTUSize())))), "subpic_height_minus1[ i ]"   );
+#endif
       WRITE_FLAG( pcSPS->getSubPicTreatedAsPicFlag(picIdx),  "subpic_treated_as_pic_flag[ i ]" );
       WRITE_FLAG( pcSPS->getLoopFilterAcrossSubpicEnabledFlag(picIdx),  "loop_filter_across_subpic_enabled_flag[ i ]" );
     }
@@ -1030,7 +1053,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   {
     WRITE_FLAG( pcSPS->getFpelMmvdEnabledFlag() ? 1 : 0,                            "sps_fpel_mmvd_enabled_flag" );
   }
+
+#if !JVET_Q0806
   WRITE_FLAG( pcSPS->getUseTriangle() ? 1: 0,                                                  "sps_triangle_enabled_flag" );
+#else
+  WRITE_FLAG( pcSPS->getUseGeo() ? 1: 0,                                                       "sps_gpm_enabled_flag" );
+#endif
 
   WRITE_FLAG(pcSPS->getUseLmcs() ? 1 : 0, "sps_lmcs_enable_flag");
   WRITE_FLAG( pcSPS->getUseLFNST() ? 1 : 0,                                                    "sps_lfnst_enabled_flag" );
@@ -1655,6 +1683,7 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
     picHeader->setDisProfFlag(0);
   }
 
+#if !JVET_Q0806
   // triangle merge candidate list size
   if (sps->getUseTriangle() && picHeader->getMaxNumMergeCand() >= 2)
   {
@@ -1668,6 +1697,21 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
       picHeader->setMaxNumTriangleCand((uint32_t)(picHeader->getMaxNumMergeCand() - (pps->getPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1() - 1)));
     }    
   }
+#else
+  // geometric merge candidate list size
+  if (sps->getUseGeo() && picHeader->getMaxNumMergeCand() >= 2)
+  {
+    if (!pps->getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1())
+    {
+      CHECK(picHeader->getMaxNumMergeCand() < picHeader->getMaxNumGeoCand(), "Incorrrect max number of gpm candidates!");
+      WRITE_UVLC(picHeader->getMaxNumMergeCand() - picHeader->getMaxNumGeoCand(), "pic_max_num_merge_cand_minus_max_num_gpm_cand");
+    }
+    else
+    {
+      picHeader->setMaxNumGeoCand((uint32_t)(picHeader->getMaxNumMergeCand() - (pps->getPPSMaxNumMergeCandMinusMaxNumGeoCandPlus1() - 1)));
+    }
+  }
+#endif
 
   // ibc merge candidate list size
   if (sps->getIBCFlag())
@@ -2310,7 +2354,11 @@ void  HLSWriter::codeConstraintInfo  ( const ConstraintInfo* cinfo )
   WRITE_FLAG(cinfo->getNoIbcConstraintFlag() ? 1 : 0, "no_ibc_constraint_flag");
   WRITE_FLAG(cinfo->getNoCiipConstraintFlag() ? 1 : 0, "no_ciip_constraint_flag");
   WRITE_FLAG(cinfo->getNoFPelMmvdConstraintFlag() ? 1 : 0, "no_fpel_mmvd_constraint_flag");
+#if !JVET_Q0806
   WRITE_FLAG(cinfo->getNoTriangleConstraintFlag() ? 1 : 0, "no_triangle_constraint_flag");
+#else
+  WRITE_FLAG(cinfo->getNoGeoConstraintFlag() ? 1 : 0, "no_gpm_constraint_flag");
+#endif
   WRITE_FLAG(cinfo->getNoLadfConstraintFlag() ? 1 : 0, "no_ladf_constraint_flag");
   WRITE_FLAG(cinfo->getNoTransformSkipConstraintFlag() ? 1 : 0, "no_transform_skip_constraint_flag");
   WRITE_FLAG(cinfo->getNoBDPCMConstraintFlag() ? 1 : 0, "no_bdpcm_constraint_flag");