diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp
index d07b3e7d2343519f6f892b3725ffe72976424e0b..e3ebc5e3406b1b262f41421bf72b7eb3134256b7 100644
--- a/source/Lib/CommonLib/TrQuant.cpp
+++ b/source/Lib/CommonLib/TrQuant.cpp
@@ -710,6 +710,13 @@ void TrQuant::getTrTypes(const TransformUnit tu, const ComponentID compID, int &
   trTypeHor = DCT2;
   trTypeVer = DCT2;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  if (isISP && tu.cu->lfnstIdx)
+  {
+    return;
+  }
+#endif
+
   if (!tu.cs->sps->getUseMTS())
     return;
 
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 3876f1699cdea85ccaa5df809c9997618b9c0158..9395092ccb70114b96e0ebaa71549fbf8bdda098 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -68,6 +68,8 @@
 
 #define JVET_P0599_INTRA_SMOOTHING_INTERP_FILT            1 // JVET-P0599: Cleanup of interpolation filtering for intra prediction
 
+#define JVET_P1026_ISP_LFNST_COMBINATION                  1 // JVET-P1026: Combination of ISP and LFNST
+
 #define JVET_P1026_MTS_SIGNALLING                         1 // JVET-P1026: CU level MTS signalling
 
 #define JVET_P0571_FIX_BS_BDPCM_CHROMA                    1 // JVET-P0571: align boundary strength for Chroma BDPCM
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 37d0a189a44dabb9618100fc77ccfa7fbf501ec6..2e198dc7019beaaae3243d89a37c1567b459794c 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -318,6 +318,30 @@ bool CU::canUseISP( const int width, const int height, const int maxTrSize )
   return true;
 }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+bool CU::canUseLfnstWithISP( const CompArea& cuArea, const ISPType ispSplitType )
+{
+  if( ispSplitType == NOT_INTRA_SUBPARTITIONS )
+  {
+    return false;
+  }
+  Size tuSize = ( ispSplitType == HOR_INTRA_SUBPARTITIONS ) ? Size( cuArea.width, CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_HORZ_SPLIT ) ) :
+    Size( CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_VERT_SPLIT ), cuArea.height );
+
+  if( !( tuSize.width >= MIN_TB_SIZEY && tuSize.height >= MIN_TB_SIZEY ) )
+  {
+    return false;
+  }
+  return true;
+}
+
+bool CU::canUseLfnstWithISP( const CodingUnit& cu, const ChannelType chType )
+{
+  CHECK( !isLuma( chType ), "Wrong ISP mode!" );
+  return CU::canUseLfnstWithISP( cu.blocks[chType == CHANNEL_TYPE_LUMA ? 0 : 1], (ISPType)cu.ispMode );
+}
+#endif
+
 uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType )
 {
   bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT;
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index dcc021f56b9366bb8f439f24c763490f4e1f9e7b..c40064f62e7c098cb7b0e35d1548b958ba3e527c 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -101,6 +101,10 @@ namespace CU
   bool      isISPFirst                ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID );
   bool      canUseISP                 ( const CodingUnit &cu,                         const ComponentID compID );
   bool      canUseISP                 ( const int width, const int height, const int maxTrSize = MAX_TB_SIZEY );
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  bool      canUseLfnstWithISP        ( const CompArea& cuArea, const ISPType ispSplitType );
+  bool      canUseLfnstWithISP        ( const CodingUnit& cu, const ChannelType chType );
+#endif
   uint32_t  getISPSplitDim            ( const int width, const int height, const PartSplit ispType );
   bool      allLumaCBFsAreZero        ( const CodingUnit& cu );
 
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 51451b03ac860ce536bda6a2264ab22630e117a4..b08e7f32d460ba9ffdff0d2088e0bcb7cba0cd95 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -3503,7 +3503,11 @@ void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID )
 void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
 {
   int chIdx = CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_CHROMA ? 1 : 0;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  if ( (cu.ispMode && !CU::canUseLfnstWithISP( cu, cu.chType ) ) ||
+#else
   if( cu.ispMode != NOT_INTRA_SUBPARTITIONS ||
+#endif
       (cu.cs->sps->getUseLFNST() && CU::isIntra(cu) && cu.mipFlag && !allowLfnstWithMip(cu.firstPU->lumaSize())) ||
     ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 )
     || ( cu.blocks[ chIdx ].lumaSize().width > cu.cs->sps->getMaxTbSize() || cu.blocks[ chIdx ].lumaSize().height > cu.cs->sps->getMaxTbSize() )
@@ -3525,14 +3529,22 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
 #else
     const bool isTrSkip = TU::getCbf(*cu.firstTU, COMPONENT_Y) && cu.firstTU->mtsIdx == MTS_SKIP;
 #endif
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if ((!cuCtx.lfnstLastScanPos && !cu.ispMode) || nonZeroCoeffNonTsCorner8x8 || isTrSkip)
+#else
     if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isTrSkip )
+#endif
 #else
 #if JVET_P0058_CHROMA_TS
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx[COMPONENT_Y] != MTS_DCT2_DCT2);
 #else
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2);
 #endif
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if ((!cuCtx.lfnstLastScanPos && !cu.ispMode) || nonZeroCoeffNonTsCorner8x8 || isNonDCT2)
+#else
     if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+#endif
 #endif
     {
       cu.lfnstIdx = 0;
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index dbc8ffa26f8e0ca82444405280eb335c870441b9..81b30591af61954791612c172b48431f0ec86180 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -1325,8 +1325,12 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C
 
   residual_lfnst_mode( cu, cuCtx );
 #if JVET_P1026_MTS_SIGNALLING
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  mts_idx            ( cu, &cuCtx );
+#else
   mts_idx            ( cu, cuCtx );
 #endif
+#endif
 }
 
 void CABACWriter::rqt_root_cbf( const CodingUnit& cu )
@@ -3031,7 +3035,11 @@ void CABACWriter::ts_flag( const TransformUnit& tu, ComponentID compID )
   DTRACE( g_trace_ctx, D_SYNTAX, "ts_flag() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tsFlag );
 }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+void CABACWriter::mts_idx( const CodingUnit& cu, CUCtx* cuCtx )
+#else
 void CABACWriter::mts_idx( const CodingUnit& cu, CUCtx& cuCtx )
+#endif
 {
   TransformUnit &tu = *cu.firstTU;
 #if JVET_P0058_CHROMA_TS
@@ -3040,8 +3048,13 @@ void CABACWriter::mts_idx( const CodingUnit& cu, CUCtx& cuCtx )
   int        mtsIdx = tu.mtsIdx;
 #endif
   
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  if( CU::isMTSAllowed( cu, COMPONENT_Y ) && cuCtx && !cuCtx->violatesMtsCoeffConstraint &&
+      cu.lfnstIdx == 0 && mtsIdx != MTS_SKIP && TU::getCbf(tu, COMPONENT_Y) )
+#else
   if( CU::isMTSAllowed( cu, COMPONENT_Y ) && !cuCtx.violatesMtsCoeffConstraint &&
       cu.lfnstIdx == 0 && mtsIdx != MTS_SKIP && TU::getCbf(tu, COMPONENT_Y) )
+#endif
   {
     int symbol = mtsIdx != MTS_DCT2_DCT2 ? 1 : 0;
     int ctxIdx = 0;
@@ -3184,7 +3197,11 @@ void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID comp
 void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
 {
   int chIdx = CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_CHROMA ? 1 : 0;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  if( ( cu.ispMode && !CU::canUseLfnstWithISP( cu, cu.chType ) ) ||
+#else
   if( cu.ispMode != NOT_INTRA_SUBPARTITIONS ||
+#endif
       (cu.cs->sps->getUseLFNST() && CU::isIntra(cu) && cu.mipFlag && !allowLfnstWithMip(cu.firstPU->lumaSize())) ||
     ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 )
     || ( cu.blocks[ chIdx ].lumaSize().width > cu.cs->sps->getMaxTbSize() || cu.blocks[ chIdx ].lumaSize().height > cu.cs->sps->getMaxTbSize() )
@@ -3205,14 +3222,22 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
 #else
     const bool isTrSkip = TU::getCbf(*cu.firstTU, COMPONENT_Y) && cu.firstTU->mtsIdx == MTS_SKIP;
 #endif
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if( (!cuCtx.lfnstLastScanPos && !cu.ispMode) || nonZeroCoeffNonTsCorner8x8 || isTrSkip )
+#else
     if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isTrSkip )
+#endif
 #else
 #if JVET_P0058_CHROMA_TS
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx[COMPONENT_Y] != MTS_DCT2_DCT2);
 #else
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2);
 #endif
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if( (!cuCtx.lfnstLastScanPos && !cu.ispMode) || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+#else
     if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+#endif
 #endif
     {
       return;
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index ec7aceb0670cc5b148d47609715e1169ecc5ff74..7e60fe96954b7a852138a428c790f87ad039b50e 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -149,7 +149,11 @@ public:
   void        residual_coding           ( const TransformUnit&          tu,       ComponentID       compID, CUCtx* cuCtx = nullptr );
 #if JVET_P1026_MTS_SIGNALLING
   void        ts_flag                   ( const TransformUnit&          tu,       ComponentID       compID );
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  void        mts_idx                   ( const CodingUnit&             cu,       CUCtx*            cuCtx  );
+#else
   void        mts_idx                   ( const CodingUnit&             cu,       CUCtx&            cuCtx  );
+#endif
 #else
   void        mts_coding                ( const TransformUnit&          tu,       ComponentID       compID );
 #endif
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 3a51961206380771d8af0ccc2b4acfae4c4c2cef..ba0a37d35e2c0827e52d6984c327561c893e9336 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -1264,7 +1264,11 @@ public:
   void setLog2MaxTransformSkipBlockSize                ( uint32_t u )    { m_log2MaxTransformSkipBlockSize  = u;       }
   bool getIntraSmoothingDisabledFlag               ()      const { return m_intraSmoothingDisabledFlag; }
   void setIntraSmoothingDisabledFlag               (bool bValue) { m_intraSmoothingDisabledFlag=bValue; }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  bool getUseFastISP                                   () const   { return m_useFastISP;    }
+#else
   bool getUseFastISP                                   ()         { return m_useFastISP;    }
+#endif
   void setUseFastISP                                   ( bool b ) { m_useFastISP  = b;   }
 
   const int* getdQPs                        () const { return m_aidQP;       }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 3187c5315d84cd99a55c865b647f9be32133c1bd..a44edc3976e5a48d79b249f26fdff612bbfa2fd8 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1712,6 +1712,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
 
 
   double dct2Cost                =   MAX_DOUBLE;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  double bestNonDCT2Cost         = MAX_DOUBLE;
+#endif
   double trGrpBestCost     [ 4 ] = { MAX_DOUBLE, MAX_DOUBLE, MAX_DOUBLE, MAX_DOUBLE };
   double globalBestCost          =   MAX_DOUBLE;
   bool   bestSelFlag       [ 4 ] = { false, false, false, false };
@@ -1732,6 +1735,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
   int grpNumMax = sps.getUseLFNST() ? m_pcEncCfg->getMTSIntraMaxCand() : 1;
 #else
   int grpNumMax = sps.getUseLFNST() ? 4 : 1;
+#endif
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  m_modeCtrl->setISPWasTested(false);
 #endif
   m_pcIntraSearch->invalidateBestModeCost();
   for( int trGrpIdx = 0; trGrpIdx < grpNumMax; trGrpIdx++ )
@@ -1792,6 +1798,16 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
             {
               continue;
             }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+            if (m_pcEncCfg->getUseFastISP() && validCandRet && !mtsFlag && !lfnstIdx)
+            {
+              m_modeCtrl->setISPMode(cu.ispMode);
+              m_modeCtrl->setISPLfnstIdx(cu.lfnstIdx);
+              m_modeCtrl->setMIPFlagISPPass(cu.mipFlag);
+              m_modeCtrl->setBestISPIntraModeRelCU(cu.ispMode ? PU::getFinalIntraMode(*cu.firstPU, CHANNEL_TYPE_LUMA) : UINT8_MAX);
+              m_modeCtrl->setBestDCT2NonISPCostRelCU(m_modeCtrl->getMtsFirstPassNoIspCost());
+            }
+#endif
 
             useIntraSubPartitions = cu.ispMode != NOT_INTRA_SUBPARTITIONS;
             if( !partitioner.isSepTree( *tempCS ) )
@@ -1869,7 +1885,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
           tempCS->fracBits = m_CABACEstimator->getEstFracBits();
           tempCS->cost     = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);
 
+#if !JVET_P1026_ISP_LFNST_COMBINATION
           double bestIspCost = cu.ispMode ? cu.isSepTree() ? tempCS->cost : tempCS->lumaCost : MAX_DOUBLE;
+#endif
 
           const double tmpCostWithoutSplitFlags = tempCS->cost;
           xEncodeDontSplit( *tempCS, partitioner );
@@ -1877,7 +1895,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
           xCheckDQP( *tempCS, partitioner );
 
           // Check if low frequency non-separable transform (LFNST) is too expensive
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          if( lfnstIdx && !cuCtx.lfnstLastScanPos && !cu.ispMode )
+#else
           if( lfnstIdx && !cuCtx.lfnstLastScanPos )
+#endif
           {
             bool cbfAtZeroDepth = cu.isSepTree() ? cu.rootCbf : std::min( cu.firstTU->blocks[ 1 ].width, cu.firstTU->blocks[ 1 ].height ) < 4 ? TU::getCbfAtDepth( *cu.firstTU, COMPONENT_Y, 0 ) : cu.rootCbf;
             if( cbfAtZeroDepth )
@@ -1890,6 +1912,12 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
           {
             dct2Cost = tempCS->cost;
           }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          else if (tmpCostWithoutSplitFlags < bestNonDCT2Cost)
+          {
+            bestNonDCT2Cost = tmpCostWithoutSplitFlags;
+          }
+#endif
 
           if( tempCS->cost < bestCS->cost )
           {
@@ -1942,19 +1970,34 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
             }
 
             //we decide to skip the non-DCT-II transforms and LFNST according to the ISP results
+#if JVET_P1026_ISP_LFNST_COMBINATION
+            if ((endMtsFlag > 0 || endLfnstIdx > 0) && (cu.ispMode || (bestCS && bestCS->cus[0]->ispMode)) && tempCS->slice->isIntra() && m_pcEncCfg->getUseFastISP())
+#else
             if ((endMtsFlag > 0 || endLfnstIdx > 0) && cu.ispMode && !mtsFlag && !lfnstIdx && tempCS->slice->isIntra() && m_pcEncCfg->getUseFastISP())
+#endif
             {
               double bestCostDct2NoIsp = m_modeCtrl->getMtsFirstPassNoIspCost();
+#if JVET_P1026_ISP_LFNST_COMBINATION
+              double bestIspCost       = m_modeCtrl->getIspCost();
+#endif
               CHECKD( bestCostDct2NoIsp <= bestIspCost, "wrong cost!" );
               double threshold = 1.4;
 
               double lfnstThreshold = 1.01 * threshold;
+#if JVET_P1026_ISP_LFNST_COMBINATION 
+              if( m_modeCtrl->getStopNonDCT2Transforms() || bestCostDct2NoIsp > bestIspCost*lfnstThreshold )
+#else
               if( bestCostDct2NoIsp > bestIspCost*lfnstThreshold )
+#endif
               {
                 endLfnstIdx = lfnstIdx;
               }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION 
+              if ( m_modeCtrl->getStopNonDCT2Transforms() || bestCostDct2NoIsp > bestIspCost*threshold )
+#else
               if( bestCostDct2NoIsp > bestIspCost*threshold )
+#endif
               {
                 skipSecondMtsPass = true;
                 m_modeCtrl->setSkipSecondMTSPass( true );
@@ -1995,6 +2038,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
       }
     }
   } //trGrpIdx
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  m_modeCtrl->setBestNonDCT2Cost(bestNonDCT2Cost);
+#endif
 }
 
 
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 36f46fdaeb1a23a59bf6ed0b43db855b6d15b82a..56da31c8cea39d411004ff8b8a635ca484d66da8 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -1578,6 +1578,16 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     {
       return false;
     }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if ( m_pcEncCfg->getUseFastISP() && relatedCU.relatedCuIsValid )
+    {
+      cuECtx.ispPredModeVal     = relatedCU.ispPredModeVal;
+      cuECtx.bestDCT2NonISPCost = relatedCU.bestDCT2NonISPCost;
+      cuECtx.relatedCuIsValid   = relatedCU.relatedCuIsValid;
+      cuECtx.bestNonDCT2Cost    = relatedCU.bestNonDCT2Cost;
+      cuECtx.bestISPIntraMode   = relatedCU.bestISPIntraMode;
+    }
+#endif
     return true;
   }
   else if (encTestmode.type == ETM_PALETTE)
@@ -1892,6 +1902,34 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
         else if( CU::isIntra( *bestCU ) )
         {
           relatedCU.isIntra   = true;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          if ( m_pcEncCfg->getUseFastISP() && cuECtx.ispWasTested && ( !relatedCU.relatedCuIsValid || bestCS->cost < relatedCU.bestCost ) )
+          {
+            // Compact data
+            int bit0 = true;
+            int bit1 = cuECtx.ispMode == NOT_INTRA_SUBPARTITIONS ? 1 : 0;
+            int bit2 = cuECtx.ispMode == VER_INTRA_SUBPARTITIONS;
+            int bit3 = cuECtx.ispLfnstIdx > 0;
+            int bit4 = cuECtx.ispLfnstIdx == 2;
+            int bit5 = cuECtx.mipFlag;
+            int bit6 = cuECtx.bestCostIsp < cuECtx.bestNonDCT2Cost * 0.95;
+            int val =
+              (bit0) |
+              (bit1 << 1) |
+              (bit2 << 2) |
+              (bit3 << 3) |
+              (bit4 << 4) |
+              (bit5 << 5) |
+              (bit6 << 6) |
+              ( cuECtx.bestPredModeDCT2 << 9 );
+            relatedCU.ispPredModeVal     = val;
+            relatedCU.bestDCT2NonISPCost = cuECtx.bestDCT2NonISPCost;
+            relatedCU.bestCost           = bestCS->cost;
+            relatedCU.bestNonDCT2Cost    = cuECtx.bestNonDCT2Cost;
+            relatedCU.bestISPIntraMode   = cuECtx.bestISPIntraMode;
+            relatedCU.relatedCuIsValid   = true;
+          }
+#endif
         }
 #if ENABLE_SPLIT_PARALLELISM
 #if REUSE_CU_RESULTS
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index 8d83878230a47d66f7f425cd3c94db53f72d3f97..38a3fc072271ed0f722bc5bc7481fe8af0bf0b31 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -201,6 +201,26 @@ struct ComprCUCtx
 #endif
     , bestCostWithoutSplitFlags( MAX_DOUBLE )
     , bestCostMtsFirstPassNoIsp( MAX_DOUBLE )
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    , bestCostIsp   ( MAX_DOUBLE )
+    , ispWasTested  ( false )
+    , bestPredModeDCT2
+                    ( UINT8_MAX )
+    , relatedCuIsValid
+                    ( false )
+    , ispPredModeVal( 0 )
+    , bestDCT2NonISPCost
+                    ( MAX_DOUBLE )
+    , bestNonDCT2Cost
+                    ( MAX_DOUBLE )
+    , bestISPIntraMode
+                    ( UINT8_MAX )
+    , mipFlag       ( false )
+    , ispMode       ( NOT_INTRA_SUBPARTITIONS )
+    , ispLfnstIdx   ( 0 )
+    , stopNonDCT2Transforms
+                    ( false )
+#endif
   {
     getAreaIdx( cs.area.Y(), *cs.pcv, cuX, cuY, cuW, cuH );
     partIdx = ( ( cuX << 8 ) | cuY );
@@ -233,6 +253,20 @@ struct ComprCUCtx
 #endif
   double                            bestCostWithoutSplitFlags;
   double                            bestCostMtsFirstPassNoIsp;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  double                            bestCostIsp;
+  bool                              ispWasTested;
+  uint16_t                          bestPredModeDCT2;
+  bool                              relatedCuIsValid;
+  uint16_t                          ispPredModeVal;
+  double                            bestDCT2NonISPCost;
+  double                            bestNonDCT2Cost;
+  uint8_t                           bestISPIntraMode;
+  bool                              mipFlag;
+  uint8_t                           ispMode;
+  uint8_t                           ispLfnstIdx;
+  bool                              stopNonDCT2Transforms;
+#endif
 
   template<typename T> T    get( int ft )       const { return typeid(T) == typeid(double) ? (T&)extraFeaturesd[ft] : T(extraFeatures[ft]); }
   template<typename T> void set( int ft, T val )      { extraFeatures [ft] = int64_t( val ); }
@@ -320,6 +354,29 @@ public:
   void   setBestCostWithoutSplitFlags ( double cost )           { m_ComprCUCtxList.back().bestCostWithoutSplitFlags = cost;         }
   double getMtsFirstPassNoIspCost     ()                  const { return m_ComprCUCtxList.back().bestCostMtsFirstPassNoIsp;         }
   void   setMtsFirstPassNoIspCost     ( double cost )           { m_ComprCUCtxList.back().bestCostMtsFirstPassNoIsp = cost;         }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  double getIspCost                   ()                  const { return m_ComprCUCtxList.back().bestCostIsp; }
+  void   setIspCost                   ( double val )            { m_ComprCUCtxList.back().bestCostIsp = val; }
+  bool   getISPWasTested              ()                  const { return m_ComprCUCtxList.back().ispWasTested; }
+  void   setISPWasTested              ( bool val )              { m_ComprCUCtxList.back().ispWasTested = val; }
+  void   setBestPredModeDCT2          ( uint16_t val )          { m_ComprCUCtxList.back().bestPredModeDCT2 = val; }
+  uint16_t getBestPredModeDCT2        ()                  const { return m_ComprCUCtxList.back().bestPredModeDCT2; }
+  bool   getRelatedCuIsValid          ()                  const { return m_ComprCUCtxList.back().relatedCuIsValid; }
+  void   setRelatedCuIsValid          ( bool val )              { m_ComprCUCtxList.back().relatedCuIsValid = val; }
+  uint16_t getIspPredModeValRelCU     ()                  const { return m_ComprCUCtxList.back().ispPredModeVal; }
+  void   setIspPredModeValRelCU       ( uint16_t val )          { m_ComprCUCtxList.back().ispPredModeVal = val; }
+  double getBestDCT2NonISPCostRelCU   ()                  const { return m_ComprCUCtxList.back().bestDCT2NonISPCost; }
+  void   setBestDCT2NonISPCostRelCU   ( double val )            { m_ComprCUCtxList.back().bestDCT2NonISPCost = val; }
+  double getBestNonDCT2Cost           ()                  const { return m_ComprCUCtxList.back().bestNonDCT2Cost; }
+  void   setBestNonDCT2Cost           ( double val )            { m_ComprCUCtxList.back().bestNonDCT2Cost = val; }
+  uint8_t getBestISPIntraModeRelCU    ()                  const { return m_ComprCUCtxList.back().bestISPIntraMode; }
+  void   setBestISPIntraModeRelCU     ( uint8_t val )           { m_ComprCUCtxList.back().bestISPIntraMode = val; }
+  void   setMIPFlagISPPass            ( bool val )              { m_ComprCUCtxList.back().mipFlag = val; }
+  void   setISPMode                   ( uint8_t val )           { m_ComprCUCtxList.back().ispMode = val; }
+  void   setISPLfnstIdx               ( uint8_t val )           { m_ComprCUCtxList.back().ispLfnstIdx = val; }
+  bool   getStopNonDCT2Transforms     ()                  const { return m_ComprCUCtxList.back().stopNonDCT2Transforms; }
+  void   setStopNonDCT2Transforms     ( bool val )              { m_ComprCUCtxList.back().stopNonDCT2Transforms = val; }
+#endif
   void setInterSearch                 (InterSearch* pcInterSearch)   { m_pcInterSearch = pcInterSearch; }
   void   setPltEnc                    ( bool b )                { m_doPlt = b; }
   bool   getPltEnc()                                      const { return m_doPlt; }
@@ -382,6 +439,14 @@ struct CodedCUInfo
   Mv   saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];
 
   uint8_t GBiIdx;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  uint16_t ispPredModeVal;
+  double   bestDCT2NonISPCost;
+  double   bestCost;
+  double   bestNonDCT2Cost;
+  bool     relatedCuIsValid;
+  uint8_t  bestISPIntraMode;
+#endif
 
 #if ENABLE_SPLIT_PARALLELISM
 
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index 4aa8664fe22d969aadd7127b925aad8e1b9ee844..1b73f92acced75e5c1b23282cee26cc9e0ae70f1 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -431,7 +431,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
     m_regIntraRDListWithCosts.clear();
     int numTotalPartsHor = (int)width  >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT));
     int numTotalPartsVer = (int)height >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT));
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    m_ispTestedModes[0].init( numTotalPartsHor, numTotalPartsVer );
+    //the total number of subpartitions is modified to take into account the cases where LFNST cannot be combined with ISP due to size restrictions
+    numTotalPartsHor = sps.getUseLFNST() && CU::canUseLfnstWithISP(cu.Y(), HOR_INTRA_SUBPARTITIONS) ? numTotalPartsHor : 0;
+    numTotalPartsVer = sps.getUseLFNST() && CU::canUseLfnstWithISP(cu.Y(), VER_INTRA_SUBPARTITIONS) ? numTotalPartsVer : 0;
+    for (int j = 1; j < NUM_LFNST_NUM_PER_SET; j++)
+    {
+      m_ispTestedModes[j].init(numTotalPartsHor, numTotalPartsVer);
+    }
+#else
     m_ispTestedModes.init(numTotalPartsHor, numTotalPartsVer);
+#endif
   }
 
 #if JVET_P0059_CHROMA_BDPCM
@@ -965,7 +976,12 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
     if ( testISP )
     {
       // we reserve positions for ISP in the common full RD list
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      const int maxNumRDModesISP = sps.getUseLFNST() ? 16 * NUM_LFNST_NUM_PER_SET : 16;
+      m_curIspLfnstIdx = 0;
+#else
       const int maxNumRDModesISP = 16;
+#endif
       for (int i = 0; i < maxNumRDModesISP; i++)
 #if JVET_P0803_COMBINED_MIP_CLEANUP
         uiRdModeList.push_back( ModeInfo( false, false, 0, INTRA_SUBPARTITIONS_RESERVED, 0 ) );
@@ -1037,10 +1053,19 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
     // just to be sure
     numModesForFullRD = ( int ) uiRdModeList.size();
     TUIntraSubPartitioner subTuPartitioner( partitioner );
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if ( testISP )
+    {
+      m_modeCtrl->setIspCost( MAX_DOUBLE );
+      m_modeCtrl->setMtsFirstPassNoIspCost( MAX_DOUBLE );
+    }
+    int bestLfnstIdx = cu.lfnstIdx;
+#else
     if( !cu.ispMode && !cu.mtsFlag )
     {
       m_modeCtrl->setMtsFirstPassNoIspCost( MAX_DOUBLE );
     }
+#endif
 
     for (int mode = -2 * int(testBDPCM); mode < (int)uiRdModeList.size(); mode++)
     {
@@ -1070,11 +1095,23 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
         {
           if (mode == numNonISPModes) // the list needs to be sorted only once
           {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+            if (m_pcEncCfg->getUseFastISP())
+            {
+              m_modeCtrl->setBestPredModeDCT2( uiBestPUMode.modeId );
+            }
+            if (!xSortISPCandList(bestCurrentCost, csBest->cost, uiBestPUMode))
+              break;
+#else
             xSortISPCandList(bestCurrentCost, csBest->cost);
+#endif
           }
           xGetNextISPMode(uiRdModeList[mode], (mode > 0 ? &uiRdModeList[mode - 1] : nullptr), Size(width, height));
           if (uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED)
             continue;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          cu.lfnstIdx = m_curIspLfnstIdx;
+#endif
         }
         uiOrgMode = uiRdModeList[mode];
       cu.mipFlag                     = uiOrgMode.mipFlg;
@@ -1100,6 +1137,12 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       bool tmpValidReturn = false;
       if( cu.ispMode )
       {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        if ( m_pcEncCfg->getUseFastISP() )
+        {
+          m_modeCtrl->setISPWasTested(true);
+        }
+#endif
         tmpValidReturn = xIntraCodingLumaISP(*csTemp, subTuPartitioner, bestCurrentCost);
         if (csTemp->tus.size() == 0)
         {
@@ -1107,11 +1150,17 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
           csTemp->cost = MAX_DOUBLE;
           continue;
         }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        // we save the data for future tests
+        m_ispTestedModes[m_curIspLfnstIdx].setModeResults((ISPType)cu.ispMode, (int)uiOrgMode.modeId, (int)csTemp->tus.size(), csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ? csTemp->cost : MAX_DOUBLE, csBest->cost);
+        csTemp->cost = !tmpValidReturn ? MAX_DOUBLE : csTemp->cost;
+#else
         if (!cu.mtsFlag && !cu.lfnstIdx)
         {
           // we save the data for future tests
           m_ispTestedModes.setModeResults((ISPType)cu.ispMode, (int)uiOrgMode.modeId, (int)csTemp->tus.size(), csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ? csTemp->cost : MAX_DOUBLE, csBest->cost);
         }
+#endif
       }
       else
       {
@@ -1168,10 +1217,22 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
           {
             bestCurrentCost = csBest->cost;
           }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          if ( cu.ispMode )
+          {
+            m_modeCtrl->setIspCost(csBest->cost);
+            bestLfnstIdx = cu.lfnstIdx;
+          }
+          else if ( testISP )
+          {
+            m_modeCtrl->setMtsFirstPassNoIspCost(csBest->cost);
+          }
+#else
           if( !cu.ispMode && !cu.mtsFlag )
           {
             m_modeCtrl->setMtsFirstPassNoIspCost( csBest->cost );
           }
+#endif
         }
         if( !cu.ispMode && !cu.bdpcmMode && csBest->cost < bestCostNonBDPCM )
         {
@@ -1200,6 +1261,9 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       }
     } // Mode loop
     cu.ispMode = uiBestPUMode.ispMod;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    cu.lfnstIdx = bestLfnstIdx;
+#endif
 
     if( validReturn )
     {
@@ -2916,7 +2980,11 @@ void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner
   }
 }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID, const int subTuIdx, const PartSplit ispType, CUCtx* cuCtx )
+#else
 void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID, const int subTuIdx, const PartSplit ispType )
+#endif
 {
   const UnitArea &currArea  = partitioner.currArea();
 
@@ -2940,7 +3008,11 @@ void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, co
 
     do
     {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      xEncCoeffQT( cs, partitioner, compID, subTuCounter, ispType, cuCtx );
+#else
       xEncCoeffQT( cs, partitioner, compID, subTuCounter, ispType );
+#endif
       subTuCounter += subTuCounter != -1 ? 1 : 0;
     } while( partitioner.nextPart( cs ) );
 
@@ -2964,9 +3036,14 @@ void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, co
 #if JVET_P1026_MTS_SIGNALLING
       if( isLuma(compID) )
       {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        m_CABACEstimator->residual_coding( currTU, compID, cuCtx );
+        m_CABACEstimator->mts_idx( *currTU.cu, cuCtx );
+#else
         CUCtx cuCtx;
         m_CABACEstimator->residual_coding( currTU, compID, &cuCtx );
         m_CABACEstimator->mts_idx( *currTU.cu, cuCtx );
+#endif
       }
       else
 #endif
@@ -2975,7 +3052,11 @@ void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, co
   }
 }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType, CUCtx* cuCtx )
+#else
 uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType )
+#endif
 {
   m_CABACEstimator->resetBits();
 
@@ -2985,7 +3066,11 @@ uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &par
 
   if( bLuma )
   {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType, cuCtx );
+#else
     xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType );
+#endif
   }
   if( bChroma )
   {
@@ -2993,6 +3078,14 @@ uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &par
     xEncCoeffQT( cs, partitioner, COMPONENT_Cr, subTuIdx, ispType );
   }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  CodingUnit& cu = *cs.getCU(partitioner.chType);
+  if ( cuCtx && bLuma && cu.isSepTree() && ( !cu.ispMode || ( cu.lfnstIdx && subTuIdx == 0 ) || ( !cu.lfnstIdx && subTuIdx == m_ispTestedModes[cu.lfnstIdx].numTotalParts[cu.ispMode - 1] - 1 ) ) )
+  {
+    m_CABACEstimator->residual_lfnst_mode(cu, *cuCtx);
+  }
+#endif
+
   uint64_t fracBits = m_CABACEstimator->getEstFracBits();
   return fracBits;
 }
@@ -3443,6 +3536,12 @@ bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitio
 
   partitioner.splitCurrArea(ispType, cs);
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  CUCtx cuCtx;
+  cuCtx.isDQPCoded = true;
+  cuCtx.isChromaQpAdjCoded = true;
+#endif
+
   do   // subpartitions loop
   {
     uint32_t   numSig = 0;
@@ -3472,7 +3571,11 @@ bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitio
       }
       else
       {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        singleTmpFracBits = xGetIntraFracBitsQT(cs, partitioner, true, false, subTuCounter, ispType, &cuCtx);
+#else
         singleTmpFracBits = xGetIntraFracBitsQT(cs, partitioner, true, false, subTuCounter, ispType);
+#endif
       }
       singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
     }
@@ -3484,7 +3587,11 @@ bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitio
     subTuCounter++;
 
     splitCbfLuma |= TU::getCbfAtDepth(*cs.getTU(partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1), COMPONENT_Y, partitioner.currTrDepth);
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    int nSubPartitions = m_ispTestedModes[cu.lfnstIdx].numTotalParts[cu.ispMode - 1];
+#else
     int nSubPartitions = m_ispTestedModes.numTotalParts[cu.ispMode - 1];
+#endif
     if (subTuCounter < nSubPartitions)
     {
       // exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance)
@@ -3533,7 +3640,9 @@ bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitio
     }
     else
     {
+#if !JVET_P1026_ISP_LFNST_COMBINATION
       cs.cost = MAX_DOUBLE;
+#endif
       earlySkipISP = true;
     }
   }
@@ -3577,6 +3686,12 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
   CodingStructure *csSplit = nullptr;
   CodingStructure *csFull  = nullptr;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  CUCtx cuCtx;
+  cuCtx.isDQPCoded = true;
+  cuCtx.isChromaQpAdjCoded = true;
+#endif
+
   if( bCheckSplit )
   {
     csSplit = &cs;
@@ -3846,7 +3961,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
         }
         else
         {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false, subTuCounter, ispType, &cuCtx );
+#else
           singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false, subTuCounter, ispType );
+#endif
         }
         singleCostTmp     = m_pcRdCost->calcRdCost( singleTmpFracBits, singleDistTmpLuma );
       }
@@ -4021,8 +4140,21 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
       //----- restore context states -----
       m_CABACEstimator->getCtx() = ctxStart;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] = false;
+      cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
+      cuCtx.lfnstLastScanPos = false;
+#if JVET_P1026_MTS_SIGNALLING
+      cuCtx.violatesMtsCoeffConstraint = false;
+#endif
+#endif
+
       //----- determine rate and r-d cost -----
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      csSplit->fracBits = xGetIntraFracBitsQT( *csSplit, partitioner, true, false, cu.ispMode ? 0 : -1, ispType, &cuCtx );
+#else
       csSplit->fracBits = xGetIntraFracBitsQT( *csSplit, partitioner, true, false, cu.ispMode ? 0 : -1, ispType );
+#endif
 
       //--- update cost ---
       csSplit->cost     = m_pcRdCost->calcRdCost(csSplit->fracBits, csSplit->dist);
@@ -4711,8 +4843,21 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
 {
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* rdModeLists[2] = { &m_ispCandListHor, &m_ispCandListVer };
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  const int curIspLfnstIdx = m_curIspLfnstIdx;
+  if (curIspLfnstIdx >= NUM_LFNST_NUM_PER_SET)
+  {
+    //All lfnst indices have been checked
+    return;
+  }
+#endif
+
   ISPType nextISPcandSplitType;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  auto& ispTestedModes = m_ispTestedModes[curIspLfnstIdx];
+#else
   auto& ispTestedModes = m_ispTestedModes;
+#endif
   const bool horSplitIsTerminated = ispTestedModes.splitIsFinished[HOR_INTRA_SUBPARTITIONS - 1];
   const bool verSplitIsTerminated = ispTestedModes.splitIsFinished[VER_INTRA_SUBPARTITIONS - 1];
   if (!horSplitIsTerminated && !verSplitIsTerminated)
@@ -4729,16 +4874,58 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
   }
   else
   {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    xFinishISPModes();
+#endif
     return;   // no more modes will be tested
   }
 
   int maxNumSubPartitions = ispTestedModes.numTotalParts[nextISPcandSplitType - 1];
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  // We try to break the split here for lfnst > 0 according to the first mode 
+  if (curIspLfnstIdx > 0 && ispTestedModes.numTestedModes[nextISPcandSplitType - 1] == 1)
+  {
+    int firstModeThisSplit = ispTestedModes.getTestedIntraMode(nextISPcandSplitType, 0);
+    int numSubPartsFirstModeThisSplit = ispTestedModes.getNumCompletedSubParts(nextISPcandSplitType, firstModeThisSplit);
+    CHECK(numSubPartsFirstModeThisSplit < 0, "wrong number of subpartitions!");
+    bool stopThisSplit = false;
+    bool stopThisSplitAllLfnsts = false;
+    if (numSubPartsFirstModeThisSplit < maxNumSubPartitions)
+    {
+      stopThisSplit = true;
+      if (m_pcEncCfg->getUseFastISP() && curIspLfnstIdx == 1 && numSubPartsFirstModeThisSplit < maxNumSubPartitions - 1)
+      {
+        stopThisSplitAllLfnsts = true;
+      }
+    }
+
+    if (stopThisSplit)
+    {
+      ispTestedModes.splitIsFinished[nextISPcandSplitType - 1] = true;
+      if (curIspLfnstIdx == 1 && stopThisSplitAllLfnsts)
+      {
+        m_ispTestedModes[2].splitIsFinished[nextISPcandSplitType - 1] = true;
+      }
+      return;
+    }
+  }
+#endif
+
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  // We try to break the split here for lfnst = 0 or all lfnst indices according to the first two modes 
+  if (curIspLfnstIdx == 0 && ispTestedModes.numTestedModes[nextISPcandSplitType - 1] == 2)
+#else
   if (ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2)
+#endif
   {
     // Split stop criteria after checking the performance of previously tested intra modes
     const int thresholdSplit1 = maxNumSubPartitions;
     bool stopThisSplit = false;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    bool stopThisSplitForAllLFNSTs = false;
+    const int thresholdSplit1ForAllLFNSTs = maxNumSubPartitions - 1;
+#endif
 
     int mode1 = ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 0);
     mode1 = mode1 == DC_IDX ? -1 : mode1;
@@ -4753,7 +4940,25 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
       if (numSubPartsBestMode1 < thresholdSplit1 && numSubPartsBestMode2 < thresholdSplit1)
       {
         stopThisSplit = true;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        if (curIspLfnstIdx == 0 && numSubPartsBestMode1 < thresholdSplit1ForAllLFNSTs && numSubPartsBestMode2 < thresholdSplit1ForAllLFNSTs)
+        {
+          stopThisSplitForAllLFNSTs = true;
+        }
+#endif
+      }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      else
+      {
+        //we stop also if the cost is MAX_DOUBLE for both modes
+        double mode1Cost = ispTestedModes.getRDCost(nextISPcandSplitType, mode1);
+        double mode2Cost = ispTestedModes.getRDCost(nextISPcandSplitType, mode2);
+        if (!(mode1Cost < MAX_DOUBLE || mode2Cost < MAX_DOUBLE))
+        {
+          stopThisSplit = true;
+        }
       }
+#endif
     }
 
     if (!stopThisSplit)
@@ -4761,27 +4966,61 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
       // 2) One split type may be discarded by comparing the number of sub-partitions of the best angle modes of both splits 
       ISPType otherSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS;
       int  numSubPartsBestMode2OtherSplit = mode2 != -1 ? ispTestedModes.getNumCompletedSubParts(otherSplit, mode2) : -1;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      if (numSubPartsBestMode2OtherSplit != -1 && numSubPartsBestMode2 != -1 && ispTestedModes.bestSplitSoFar != nextISPcandSplitType)
+#else
       if (numSubPartsBestMode2OtherSplit != -1 && numSubPartsBestMode2 != -1)
+#endif
       {
         if (numSubPartsBestMode2OtherSplit > numSubPartsBestMode2)
         {
           stopThisSplit = true;
         }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        // both have the same number of subpartitions
+        else if (numSubPartsBestMode2OtherSplit == numSubPartsBestMode2)
+#else
         else if (numSubPartsBestMode2OtherSplit == numSubPartsBestMode2 && numSubPartsBestMode2OtherSplit == maxNumSubPartitions)
+#endif
         {
-          double rdCostBestMode2ThisSplit = ispTestedModes.getRDCost(nextISPcandSplitType, mode2);
-          double rdCostBestMode2OtherSplit = ispTestedModes.getRDCost(otherSplit, mode2);
-          double threshold = 1.3;
-          if (rdCostBestMode2ThisSplit == MAX_DOUBLE || rdCostBestMode2OtherSplit < rdCostBestMode2ThisSplit * threshold)
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          // both have the maximum number of subpartitions, so it compares RD costs to decide
+          if (numSubPartsBestMode2OtherSplit == maxNumSubPartitions)
+          {
+#endif
+            double rdCostBestMode2ThisSplit = ispTestedModes.getRDCost(nextISPcandSplitType, mode2);
+            double rdCostBestMode2OtherSplit = ispTestedModes.getRDCost(otherSplit, mode2);
+            double threshold = 1.3;
+            if (rdCostBestMode2ThisSplit == MAX_DOUBLE || rdCostBestMode2OtherSplit < rdCostBestMode2ThisSplit * threshold)
+            {
+              stopThisSplit = true;
+            }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+          }
+          else // none of them reached the maximum number of subpartitions with the best angle modes, so it compares the results with the the planar mode
           {
-            stopThisSplit = true;
+            int  numSubPartsBestMode1OtherSplit = mode1 != -1 ? ispTestedModes.getNumCompletedSubParts(otherSplit, mode1) : -1;
+            if (numSubPartsBestMode1OtherSplit != -1 && numSubPartsBestMode1 != -1 && numSubPartsBestMode1OtherSplit > numSubPartsBestMode1)
+            {
+              stopThisSplit = true;
+            }
           }
+#endif
         }
       }
     }
     if (stopThisSplit)
     {
       ispTestedModes.splitIsFinished[nextISPcandSplitType - 1] = true;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      if (stopThisSplitForAllLFNSTs)
+      {
+        for (int lfnstIdx = 1; lfnstIdx < NUM_LFNST_NUM_PER_SET; lfnstIdx++)
+        {
+          m_ispTestedModes[lfnstIdx].splitIsFinished[nextISPcandSplitType - 1] = true;
+        }
+      }
+#endif
       return;
     }
   }
@@ -4797,6 +5036,9 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
     {
       if (ispTestedModes.bestSplitSoFar != candidate.ispMod || ispTestedModes.bestModeSoFar == PLANAR_IDX)
       {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+        ispTestedModes.splitIsFinished[nextISPcandSplitType - 1] = true;
+#endif
         return;
       }
     }
@@ -4804,20 +5046,45 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
     bool testCandidate = true;
 
     // we look for a reference mode that has already been tested within the window and decide to test the new one according to the reference mode costs
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    if (maxNumSubPartitions > 2 && (curIspLfnstIdx > 0 || (candidate.modeId >= DC_IDX && ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2)))
+#else
     if (candidate.modeId >= DC_IDX && maxNumSubPartitions > 2 && ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2)
+#endif
     {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      int       refLfnstIdx = -1;
+#endif
       const int angWindowSize = 5;
       int       numSubPartsLeftMode, numSubPartsRightMode, numSubPartsRefMode, leftIntraMode = -1, rightIntraMode = -1;
       int       windowSize = candidate.modeId > DC_IDX ? angWindowSize : 1;
       int       numSamples = cuSize.width << floorLog2(cuSize.height);
       int       numSubPartsLimit = numSamples >= 256 ? maxNumSubPartitions - 1 : 2;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      xFindAlreadyTestedNearbyIntraModes(curIspLfnstIdx, (int)candidate.modeId, &refLfnstIdx, &leftIntraMode, &rightIntraMode, (ISPType)candidate.ispMod, windowSize);
+#else
       xFindAlreadyTestedNearbyIntraModes((int)candidate.modeId, &leftIntraMode, &rightIntraMode, (ISPType)candidate.ispMod, windowSize);
+#endif
 
-      numSubPartsLeftMode = leftIntraMode != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, leftIntraMode) : -1;
-      numSubPartsRightMode = rightIntraMode != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, rightIntraMode) : -1;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      if (refLfnstIdx != -1 && refLfnstIdx != curIspLfnstIdx)
+      {
+        CHECK(leftIntraMode != candidate.modeId || rightIntraMode != candidate.modeId, "wrong intra mode and lfnstIdx values!");
+        numSubPartsRefMode = m_ispTestedModes[refLfnstIdx].getNumCompletedSubParts((ISPType)candidate.ispMod, candidate.modeId);
+        CHECK(numSubPartsRefMode <= 0, "Wrong value of the number of subpartitions completed!");
+
+      }
+      else
+      {
+#endif
+        numSubPartsLeftMode = leftIntraMode != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, leftIntraMode) : -1;
+        numSubPartsRightMode = rightIntraMode != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, rightIntraMode) : -1;
 
-      numSubPartsRefMode = std::max(numSubPartsLeftMode, numSubPartsRightMode);
+        numSubPartsRefMode = std::max(numSubPartsLeftMode, numSubPartsRightMode);
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      }
+#endif
 
       if (numSubPartsRefMode > 0)
       {
@@ -4831,34 +5098,112 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode,
       modeInfo = candidate;
     }
   }
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  else
+  {
+    //the end of the list was reached, so the split is invalidated
+    ispTestedModes.splitIsFinished[nextISPcandSplitType - 1] = true;
+  }
+#endif
 }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+void IntraSearch::xFindAlreadyTestedNearbyIntraModes(int lfnstIdx, int currentIntraMode, int* refLfnstIdx, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize)
+#else
 void IntraSearch::xFindAlreadyTestedNearbyIntraModes(int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize)
+#endif
 {
   bool leftModeFound = false, rightModeFound = false;
   *leftIntraMode = -1;
   *rightIntraMode = -1;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  *refLfnstIdx = -1;
+#endif
   const unsigned st = ispOption - 1;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  //first we check if the exact intra mode was already tested for another lfnstIdx value
+  if (lfnstIdx > 0)
+  {
+    bool sameIntraModeFound = false;
+    if (lfnstIdx == 2 && m_ispTestedModes[1].modeHasBeenTested[currentIntraMode][st])
+    {
+      sameIntraModeFound = true;
+      *refLfnstIdx = 1;
+    }
+    else if (m_ispTestedModes[0].modeHasBeenTested[currentIntraMode][st])
+    {
+      sameIntraModeFound = true;
+      *refLfnstIdx = 0;
+    }
+
+    if (sameIntraModeFound)
+    {
+      *leftIntraMode = currentIntraMode;
+      *rightIntraMode = currentIntraMode;
+      return;
+    }
+  }
+
+  //The mode has not been checked for another lfnstIdx value, so now we look for a similar mode within a window using the same lfnstIdx 
+#endif
   for (int k = 1; k <= windowSize; k++)
   {
     int off = currentIntraMode - 2 - k;
     int leftMode = (off < 0) ? NUM_LUMA_MODE + off : currentIntraMode - k;
     int rightMode = currentIntraMode > DC_IDX ? (((int)currentIntraMode - 2 + k) % 65) + 2 : PLANAR_IDX;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+    leftModeFound  = leftMode  != (int)currentIntraMode ? m_ispTestedModes[lfnstIdx].modeHasBeenTested[leftMode][st]  : false;
+    rightModeFound = rightMode != (int)currentIntraMode ? m_ispTestedModes[lfnstIdx].modeHasBeenTested[rightMode][st] : false;
+#else
     leftModeFound = leftMode != (int)currentIntraMode ? m_ispTestedModes.modeHasBeenTested[leftMode][st] : false;
     rightModeFound = rightMode != (int)currentIntraMode ? m_ispTestedModes.modeHasBeenTested[rightMode][st] : false;
+#endif
     if (leftModeFound || rightModeFound)
     {
       *leftIntraMode = leftModeFound ? leftMode : -1;
       *rightIntraMode = rightModeFound ? rightMode : -1;
+#if JVET_P1026_ISP_LFNST_COMBINATION
+      *refLfnstIdx = lfnstIdx;
+#endif
       break;
     }
   }
 }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+//It prepares the list of potential intra modes candidates that will be tested using RD costs
+bool IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost, ModeInfo bestNonISPMode)
+#else
 void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
+#endif
 {
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  int bestISPModeInRelCU = -1;
+  m_modeCtrl->setStopNonDCT2Transforms(false);
+
+  if (m_pcEncCfg->getUseFastISP())
+  {
+    //we check if the ISP tests can be cancelled
+    double thSkipISP = 1.4;
+    if (bestNonISPCost > bestCostSoFar * thSkipISP)
+    {
+      for (int splitIdx = 0; splitIdx < NUM_INTRA_SUBPARTITIONS_MODES - 1; splitIdx++)
+      {
+        for (int j = 0; j < NUM_LFNST_NUM_PER_SET; j++)
+        {
+          m_ispTestedModes[j].splitIsFinished[splitIdx] = true;
+        }
+      }
+      return false;
+    }
+    if (!updateISPStatusFromRelCU(bestNonISPCost, bestNonISPMode, bestISPModeInRelCU))
+    {
+      return false;
+    }
+  }
+#else
   if (m_pcEncCfg->getUseFastISP())
   {
     double thSkipISP = 1.4;
@@ -4871,6 +5216,7 @@ void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
       return;
     }
   }
+#endif
 
   for (int k = 0; k < m_ispCandListHor.size(); k++)
   {
@@ -4902,6 +5248,79 @@ void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
 
   ModeInfo refMode = origHadList.at(0);
   auto* destListPtr = &m_ispCandListHor;
+  #if JVET_P1026_ISP_LFNST_COMBINATION
+  //List creation 
+
+  if (m_pcEncCfg->getUseFastISP() && bestISPModeInRelCU != -1) //RelCU intra mode
+  {
+#if JVET_P0803_COMBINED_MIP_CLEANUP
+   destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mipTrFlg, refMode.mRefId, refMode.ispMod, bestISPModeInRelCU));
+#else
+   destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, bestISPModeInRelCU));
+#endif
+    modeIsInList[bestISPModeInRelCU] = true;
+  }
+
+  // Planar
+  if (!modeIsInList[mode1])
+  {
+#if JVET_P0803_COMBINED_MIP_CLEANUP
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mipTrFlg, refMode.mRefId, refMode.ispMod, mode1));
+#else
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, mode1));
+#endif
+    modeIsInList[mode1] = true;
+  }
+  // Best angle in regular intra
+  if (mode2 != -1 && !modeIsInList[mode2])
+  {
+#if JVET_P0803_COMBINED_MIP_CLEANUP
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mipTrFlg, refMode.mRefId, refMode.ispMod, mode2));
+#else
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, mode2));
+#endif
+    modeIsInList[mode2] = true;
+  }
+  // Remaining regular intra modes that were full RD tested (except DC, which is added after the angles from regular intra)
+  int dcModeIndex = -1;
+  for (int remModeIdx = 0; remModeIdx < m_regIntraRDListWithCosts.size(); remModeIdx++)
+  {
+    int currentMode = m_regIntraRDListWithCosts.at(remModeIdx).modeId;
+    if (currentMode != mode1 && currentMode != mode2 && !modeIsInList[currentMode])
+    {
+      if (currentMode > DC_IDX)
+      {
+#if JVET_P0803_COMBINED_MIP_CLEANUP
+        destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mipTrFlg, refMode.mRefId, refMode.ispMod, currentMode));
+#else
+        destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, currentMode));
+#endif
+        modeIsInList[currentMode] = true;
+      }
+      else if (currentMode == DC_IDX)
+      {
+        dcModeIndex = remModeIdx;
+      }
+    }
+  }
+
+  // DC is added after the angles from regular intra
+  if (dcModeIndex != -1 && !modeIsInList[DC_IDX])
+  {
+#if JVET_P0803_COMBINED_MIP_CLEANUP
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mipTrFlg, refMode.mRefId, refMode.ispMod, DC_IDX));
+#else
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, DC_IDX));
+#endif
+    modeIsInList[DC_IDX] = true;
+  }
+
+  // We add extra candidates to the list that will only be tested if ISP is likely to win
+  for (int j = 0; j < NUM_LFNST_NUM_PER_SET; j++)
+  {
+    m_ispTestedModes[j].numOrigModesToTest = (int)destListPtr->size();
+  }
+#else
   // 1) Planar
 #if JVET_P0803_COMBINED_MIP_CLEANUP
   destListPtr->push_back( ModeInfo( refMode.mipFlg, refMode.mipTrFlg, refMode.mRefId, refMode.ispMod, mode1 ) );
@@ -4954,6 +5373,7 @@ void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
 
   // 5) We add extra candidates to the list that will only be tested if ISP is likely to win
   m_ispTestedModes.numOrigModesToTest = (int)destListPtr->size();
+#endif
   const int addedModesFromHadList = 3;
   int       newModesAdded = 0;
 
@@ -4974,6 +5394,13 @@ void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
     }
   }
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  if (m_pcEncCfg->getUseFastISP() && bestISPModeInRelCU != -1)
+  {
+    destListPtr->resize(1);
+  }
+#endif
+
   // Copy modes to other split-type list
   m_ispCandListVer = m_ispCandListHor;
   for (int i = 0; i < m_ispCandListVer.size(); i++)
@@ -4982,9 +5409,162 @@ void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
   }
 
   // Reset the tested modes information to 0
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  for (int j = 0; j < NUM_LFNST_NUM_PER_SET; j++)
+  {
+    for (int i = 0; i < m_ispCandListHor.size(); i++)
+    {
+      m_ispTestedModes[j].clearISPModeInfo(m_ispCandListHor[i].modeId);
+    }
+  }
+  return true;
+#else
   for (int i = 0; i < m_ispCandListHor.size(); i++)
   {
     m_ispTestedModes.clearISPModeInfo(m_ispCandListHor[i].modeId);
   }
+#endif
+}
+
+#if JVET_P1026_ISP_LFNST_COMBINATION
+void IntraSearch::xSortISPCandListLFNST()
+{
+  //It resorts the list of intra mode candidates for lfnstIdx > 0 by checking the RD costs for lfnstIdx = 0
+  ISPTestedModesInfo& ispTestedModesRef = m_ispTestedModes[0];
+  for (int splitIdx = 0; splitIdx < NUM_INTRA_SUBPARTITIONS_MODES - 1; splitIdx++)
+  {
+    ISPType ispMode = splitIdx ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS;
+    if (!m_ispTestedModes[m_curIspLfnstIdx].splitIsFinished[splitIdx] && ispTestedModesRef.testedModes[splitIdx].size() > 1)
+    {
+      auto& candList   = ispMode == HOR_INTRA_SUBPARTITIONS ? m_ispCandListHor : m_ispCandListVer;
+      int bestModeId   = candList[1].modeId > DC_IDX ? candList[1].modeId : -1;
+      int bestSubParts = candList[1].modeId > DC_IDX ? ispTestedModesRef.getNumCompletedSubParts(ispMode, bestModeId) : -1;
+      double bestCost  = candList[1].modeId > DC_IDX ? ispTestedModesRef.getRDCost(ispMode, bestModeId) : MAX_DOUBLE;
+      for (int i = 0; i < candList.size(); i++)
+      {
+        const int candSubParts = ispTestedModesRef.getNumCompletedSubParts(ispMode, candList[i].modeId);
+        const double candCost = ispTestedModesRef.getRDCost(ispMode, candList[i].modeId);
+        if (candSubParts > bestSubParts || candCost < bestCost)
+        {
+          bestModeId = candList[i].modeId;
+          bestCost = candCost;
+          bestSubParts = candSubParts;
+        }
+      }
+
+      if (bestModeId != -1)
+      {
+        if (bestModeId != candList[0].modeId)
+        {
+          auto prevMode = candList[0];
+          candList[0].modeId = bestModeId;
+          for (int i = 1; i < candList.size(); i++)
+          {
+            auto nextMode = candList[i];
+            candList[i] = prevMode;
+            if (nextMode.modeId == bestModeId)
+            {
+              break;
+            }
+            prevMode = nextMode;
+          }
+        }
+      }
+    }
+  }
+}
+
+bool IntraSearch::updateISPStatusFromRelCU( double bestNonISPCostCurrCu, ModeInfo bestNonISPModeCurrCu, int& bestISPModeInRelCU )
+{
+  //It compares the data of a related CU with the current CU to cancel or reduce the ISP tests
+  bestISPModeInRelCU = -1;
+  if (m_modeCtrl->getRelatedCuIsValid())
+  {
+    double bestNonISPCostRelCU = m_modeCtrl->getBestDCT2NonISPCostRelCU();
+    double costRatio           = bestNonISPCostCurrCu / bestNonISPCostRelCU;
+    bool   bestModeRelCuIsMip  = (m_modeCtrl->getIspPredModeValRelCU() >> 5) & 0x1;
+    bool   bestModeCurrCuIsMip = bestNonISPModeCurrCu.mipFlg;
+    int    relatedCuIntraMode  = m_modeCtrl->getIspPredModeValRelCU() >> 9;
+    bool   isSameTypeOfMode    = (bestModeRelCuIsMip && bestModeCurrCuIsMip) || (!bestModeRelCuIsMip && !bestModeCurrCuIsMip);
+    bool   bothModesAreAngular = bestNonISPModeCurrCu.modeId > DC_IDX && relatedCuIntraMode > DC_IDX;
+    bool   modesAreComparable  = isSameTypeOfMode && (bestModeCurrCuIsMip || bestNonISPModeCurrCu.modeId == relatedCuIntraMode || (bothModesAreAngular && abs(relatedCuIntraMode - (int)bestNonISPModeCurrCu.modeId) <= 5));
+    int    status              = m_modeCtrl->getIspPredModeValRelCU();
+
+    if ((status & 0x3) == 0x3) //ISP was not selected in the relCU
+    {
+      double bestNonDCT2Cost = m_modeCtrl->getBestNonDCT2Cost();
+      double ratioWithNonDCT2 = bestNonDCT2Cost / bestNonISPCostRelCU;
+      double margin = ratioWithNonDCT2 < 0.95 ? 0.2 : 0.1;
+
+      if (costRatio > 1 - margin && costRatio < 1 + margin && modesAreComparable)
+      {
+        for (int lfnstVal = 0; lfnstVal < NUM_LFNST_NUM_PER_SET; lfnstVal++)
+        {
+          m_ispTestedModes[lfnstVal].splitIsFinished[HOR_INTRA_SUBPARTITIONS - 1] = true;
+          m_ispTestedModes[lfnstVal].splitIsFinished[VER_INTRA_SUBPARTITIONS - 1] = true;
+        }
+        return false;
+      }
+    }
+    else if ((status & 0x3) == 0x1) //ISP was selected in the relCU
+    {
+      double margin = 0.05;
+
+      if (costRatio > 1 - margin && costRatio < 1 + margin && modesAreComparable)
+      {
+        int  ispSplitIdx = (m_modeCtrl->getIspPredModeValRelCU() >> 2) & 0x1;
+        bool lfnstIdxIsNot0 = (bool)((m_modeCtrl->getIspPredModeValRelCU() >> 3) & 0x1);
+        bool lfnstIdxIs2 = (bool)((m_modeCtrl->getIspPredModeValRelCU() >> 4) & 0x1);
+        int  lfnstIdx = !lfnstIdxIsNot0 ? 0 : lfnstIdxIs2 ? 2 : 1;
+        bestISPModeInRelCU = (int)m_modeCtrl->getBestISPIntraModeRelCU();
+
+        for (int splitIdx = 0; splitIdx < NUM_INTRA_SUBPARTITIONS_MODES - 1; splitIdx++)
+        {
+          for (int lfnstVal = 0; lfnstVal < NUM_LFNST_NUM_PER_SET; lfnstVal++)
+          {
+            if (lfnstVal == lfnstIdx && splitIdx == ispSplitIdx)
+            {
+              continue;
+            }
+            m_ispTestedModes[lfnstVal].splitIsFinished[splitIdx] = true;
+          }
+        }
+
+        bool stopNonDCT2Transforms = (bool)((m_modeCtrl->getIspPredModeValRelCU() >> 6) & 0x1);
+        m_modeCtrl->setStopNonDCT2Transforms(stopNonDCT2Transforms);
+      }
+    }
+    else
+    {
+      THROW("Wrong ISP relCU status");
+    }
+  }
+
+  return true;
 }
 
+void IntraSearch::xFinishISPModes()
+{
+  //Continue to the next lfnst index 
+  m_curIspLfnstIdx++;
+
+  if (m_curIspLfnstIdx < NUM_LFNST_NUM_PER_SET)
+  {
+    //Check if LFNST is applicable
+    if (m_curIspLfnstIdx == 1)
+    {
+      bool canTestLFNST = false;
+      for (int lfnstIdx = 1; lfnstIdx < NUM_LFNST_NUM_PER_SET; lfnstIdx++)
+      {
+        canTestLFNST |= !m_ispTestedModes[lfnstIdx].splitIsFinished[HOR_INTRA_SUBPARTITIONS - 1] || !m_ispTestedModes[lfnstIdx].splitIsFinished[VER_INTRA_SUBPARTITIONS - 1];
+      }
+      if (canTestLFNST)
+      {
+        //Construct the intra modes candidates list for the lfnst > 0 cases
+        xSortISPCandListLFNST();
+      }
+    }
+  }
+}
+#endif
+
diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h
index 9d780fa555c651702a3d00f446e2d3c6cbeb8ad8..fa157f153fc1fb44d02a993f904d9c4efe1d4411 100644
--- a/source/Lib/EncoderLib/IntraSearch.h
+++ b/source/Lib/EncoderLib/IntraSearch.h
@@ -345,7 +345,12 @@ private:
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_ispCandListHor, m_ispCandListVer;
   static_vector<ModeInfoWithCost, FAST_UDI_MAX_RDMODE_NUM> m_regIntraRDListWithCosts;
 
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  ISPTestedModesInfo m_ispTestedModes[NUM_LFNST_NUM_PER_SET];
+  int m_curIspLfnstIdx;
+#else
   ISPTestedModesInfo m_ispTestedModes;
+#endif
 
   //cost variables for the EMT algorithm and new modes list
   double     m_bestModeCostStore[ NUM_LFNST_NUM_PER_SET ];                                    // RD cost of the best mode for each PU using DCT2
@@ -448,12 +453,19 @@ protected:
 
   void     xEncIntraHeader                         ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1 );
   void     xEncSubdivCbfQT                         ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP );
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  uint64_t xGetIntraFracBitsQT                     ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP, CUCtx * cuCtx = nullptr  );
+#else
   uint64_t xGetIntraFracBitsQT                     ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP );
+#endif
   uint64_t xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner& pm, const ComponentID compID );
 
   uint64_t xGetIntraFracBitsQTChroma(TransformUnit& tu, const ComponentID &compID);
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  void xEncCoeffQT                                 ( CodingStructure &cs, Partitioner& pm, const ComponentID compID, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP, CUCtx * cuCtx = nullptr );
+#else
   void xEncCoeffQT                                 ( CodingStructure &cs, Partitioner& pm, const ComponentID compID, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP );
-
+#endif
 
   void xIntraCodingTUBlock        (TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2 = 0, uint32_t* numSig = nullptr, std::vector<TrMode>* trModes=nullptr, const bool loadTr=false );
 
@@ -485,8 +497,16 @@ protected:
   void   preCalcPLTIndex (      CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp);
 #endif
   void xGetNextISPMode                    ( ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize );
+#if JVET_P1026_ISP_LFNST_COMBINATION
+  bool xSortISPCandList                   ( double bestCostSoFar, double bestNonISPCost, ModeInfo bestNonISPMode );
+  void xSortISPCandListLFNST              ( );
+  void xFindAlreadyTestedNearbyIntraModes ( int currentLfnstIdx, int currentIntraMode, int* refLfnstIdx, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize );
+  bool updateISPStatusFromRelCU           ( double bestNonISPCostCurrCu, ModeInfo bestNonISPModeCurrCu, int& bestISPModeInRelCU );
+  void xFinishISPModes                    ( );
+#else
   void xFindAlreadyTestedNearbyIntraModes ( int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize );
   void xSortISPCandList                   ( double bestCostSoFar, double bestNonISPCost );
+#endif
 };// END CLASS DEFINITION EncSearch
 
 //! \}