From aaa55ef53458f35961c1548007a4f7ab8f0337b5 Mon Sep 17 00:00:00 2001
From: Ted <jhuhong-jheng@kwai.com>
Date: Tue, 19 Oct 2021 22:34:35 -0700
Subject: [PATCH] JVET-X0148: PDPC handling for TIMD

---
 source/Lib/CommonLib/IntraPrediction.cpp | 75 ++++++++++++++++++++++++
 source/Lib/CommonLib/IntraPrediction.h   |  3 +
 source/Lib/CommonLib/TypeDef.h           |  1 +
 3 files changed, 79 insertions(+)

diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index 45ef7265e..5e5a66392 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -379,6 +379,58 @@ void IntraPrediction::xIntraPredTimdAngLuma(Pel* pDstBuf, const ptrdiff_t dstStr
     deltaPos += intraPredAngle;
   }
 }
+
+#if JVET_X0148_TIMD_PDPC
+void IntraPrediction::xIntraPredPlanarDcPdpc(const CPelBuf &pSrc, Pel* pDst, int iDstStride, int width, int height, bool ciipPDPC)
+{
+  const int iWidth  = width;
+  const int iHeight = height;
+  const int scale  = ((floorLog2(iWidth) - 2 + floorLog2(iHeight) - 2 + 2) >> 2);
+  CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31");
+  const Pel *srcLeft = pSrc.bufAt(1, 1);
+#if CIIP_PDPC
+  if (ciipPDPC)
+  {
+    for (int y = 0; y < iHeight; y++)
+    {
+      const int  wT     = 32 >> std::min(31, ((y << 1) >> scale));
+      const Pel  left    = *srcLeft;
+      const Pel *srcTop = pSrc.buf + 1;
+      for (int x = 0; x < iWidth; x++)
+      {
+        const int wL  = 32 >> std::min(31, ((x << 1) >> scale));
+        const Pel top = *srcTop;
+        pDst[x]        = ((wL * left + wT * top + 32) >> 6);
+
+        srcTop++;
+      }
+      srcLeft++;
+      pDst += iDstStride;
+    }
+  }
+  else
+#endif
+    for (int y = 0; y < iHeight; y++)
+    {
+      const int  wT     = 32 >> std::min(31, ((y << 1) >> scale));
+      const Pel  left   = *srcLeft;
+      const Pel *srcTop = pSrc.buf + 1;
+
+      for (int x = 0; x < iWidth; x++)
+      {
+        const int wL  = 32 >> std::min(31, ((x << 1) >> scale));
+        const Pel top = *srcTop;
+        const Pel val = pDst[x];
+
+        pDst[x] = val + ((wL * (left - val) + wT * (top - val) + 32) >> 6);
+        srcTop++;
+      }
+
+      srcLeft++;
+      pDst += iDstStride;
+    }
+}
+#endif
 #endif
 
 // ====================================================================================================================
@@ -519,6 +571,17 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
   }
 #endif
 
+#if JVET_X0148_TIMD_PDPC
+#if CIIP_PDPC
+  if ((m_ipaParam.applyPDPC || pu.ciipPDPC) && (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX))
+#else
+  if (m_ipaParam.applyPDPC && (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX))
+#endif
+  {
+    xIntraPredPlanarDcPdpc(srcBuf, piPred.buf, piPred.stride, iWidth, iHeight, pu.ciipPDPC);
+  }
+#endif
+
 #if ENABLE_DIMD
   if (pu.cu->dimd && pu.cu->dimd_is_blend && isLuma(compID))
   {
@@ -673,6 +736,16 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
     default:          xPredIntraAng(srcBuf, predFusion, channelType, clpRng, bExtIntraDir); break;
     }
 
+#if JVET_X0148_TIMD_PDPC
+#if CIIP_PDPC
+    if ((m_ipaParam.applyPDPC || pu.ciipPDPC) && (pu.cu->timdModeSecondary == PLANAR_IDX || pu.cu->timdModeSecondary == DC_IDX))
+#else
+    if (m_ipaParam.applyPDPC && (pu.cu->timdModeSecondary == PLANAR_IDX || pu.cu->timdModeSecondary == DC_IDX))
+#endif
+    {
+      xIntraPredPlanarDcPdpc(srcBuf, m_tempBuffer[1].getBuf(localUnitArea.Y()).buf, m_tempBuffer[1].getBuf(localUnitArea.Y()).stride, iWidth, iHeight, pu.ciipPDPC);
+    }
+#endif
     m_ipaParam.applyPDPC = applyPdpc;
 
     // do blending
@@ -696,6 +769,7 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
   }
 #endif
 
+#if !JVET_X0148_TIMD_PDPC
 #if CIIP_PDPC
   if (m_ipaParam.applyPDPC || pu.ciipPDPC)
 #else
@@ -754,6 +828,7 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
       }
     }
   }
+#endif
 }
 
 void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred, const PredictionUnit &pu, const CompArea& chromaArea, int intraDir)
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index b132622a2..d89f5d2e7 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -228,6 +228,9 @@ public:
 #if GRAD_PDPC
   void xIntraPredTimdAngGradPdpc  (Pel* pDsty, const int dstStride, Pel* refMain, Pel* refSide, const int width, const int height, int xOffset, int yOffset, int scale, int deltaPos, int intraPredAngle, const ClpRng& clpRng);
 #endif
+#if JVET_X0148_TIMD_PDPC
+  void xIntraPredPlanarDcPdpc     (const CPelBuf &pSrc, Pel *pDst, int iDstStride, int width, int height, bool ciipPDPC);
+#endif
 #endif
   // Angular Intra
   void predIntraAng               ( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu);
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 18e9d80ea..a91ba24a3 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -113,6 +113,7 @@
 #define JVET_V0130_INTRA_TMP                              1 // JVET-V0130: template matching prediction
 #define JVET_W0069_TMP_BOUNDARY								            1 // JVET-W0069: boundary handling for TMP
 #define JVET_W0123_TIMD_FUSION                            1 // JVET-W0123: Template based intra mode derivation and fusion
+#define JVET_X0148_TIMD_PDPC         JVET_W0123_TIMD_FUSION // JVET-X0148: PDPC handling for TIMD
 #if ENABLE_DIMD || JVET_W0123_TIMD_FUSION
 #define JVET_X0149_TIMD_DIMD_LUT                          1 // JVET-X0149: LUT-based derivation of DIMD and TIMD
 #endif
-- 
GitLab