[x265] [PATCH] encoder: refactor frame encoder recon row synchronization

Steve Borho steve at borho.org
Tue Jan 28 07:30:35 CET 2014


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1390889848 21600
#      Tue Jan 28 00:17:28 2014 -0600
# Branch stable
# Node ID 55953908a310e9a1a556f3ec90fa934c5569dd60
# Parent  dd0ef09680fe454b90000c24098d904042605bc9
encoder: refactor frame encoder recon row synchronization

The previous approach depended on a common event (owned by TComPic) being
triggered multiple times for each row, one trigger per referencing frame, but I
believe this was fragile as one frame encoder could steal notifications from
another.

In the new scheme, each frame encoder waits on its own sync event when it blocks
for recon pixels. When a frame encoder finishes reconstructing a CU row, it
calls a top-level encoder function which determines if any frame encoders are
blocked on that POC and wakes them up.

This should prevent deadlocks from frame encoder synchronization

diff -r dd0ef09680fe -r 55953908a310 source/Lib/TLibCommon/TComPic.h
--- a/source/Lib/TLibCommon/TComPic.h	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/Lib/TLibCommon/TComPic.h	Tue Jan 28 00:17:28 2014 -0600
@@ -79,7 +79,6 @@
     //** Frame Parallelism - notification between FrameEncoders of available motion reference rows **
     volatile uint32_t     m_reconRowCount;      // count of CTU rows completely reconstructed and extended for motion reference
     volatile uint32_t     m_countRefEncoders;   // count of FrameEncoder threads monitoring m_reconRowCount
-    Event                 m_reconRowWait;       // event triggered m_countRefEncoders times each time a recon row is completed
     void*                 m_userData;           // user provided pointer passed in with this picture
     int64_t               m_pts;                // user provided presentation time stamp
 
diff -r dd0ef09680fe -r 55953908a310 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/encoder/encoder.cpp	Tue Jan 28 00:17:28 2014 -0600
@@ -185,6 +185,20 @@
     m_encodeStartTime = x265_mdate();
 }
 
+/* Called when a frame encoder has completed a CTU row of reconstructed
+ * pixels and extended them; making them available for use as reference.
+ * It calls this function with its POC, so the top encoder may waken any
+ * other frame encoders that were waiting for a row of recon pixels from
+ * this picture */
+void Encoder::signalReconRowCompleted(int poc)
+{
+    for (int i = 0; i < param.frameNumThreads; i++)
+    {
+        if (m_frameEncoder[i].m_blockRefPOC == poc)
+            m_frameEncoder[i].m_reconRowWait.trigger();
+    }
+}
+
 int Encoder::getStreamHeaders(NALUnitEBSP **nalunits)
 {
     return m_frameEncoder->getStreamHeaders(nalunits);
diff -r dd0ef09680fe -r 55953908a310 source/encoder/encoder.h
--- a/source/encoder/encoder.h	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/encoder/encoder.h	Tue Jan 28 00:17:28 2014 -0600
@@ -136,6 +136,8 @@
 
     void updateVbvPlan(RateControl* rc);
 
+    void signalReconRowCompleted(int poc);
+
 protected:
 
     uint64_t calculateHashAndPSNR(TComPic* pic, NALUnitEBSP **nalunits); // Returns total number of bits for encoded pic
diff -r dd0ef09680fe -r 55953908a310 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/encoder/frameencoder.cpp	Tue Jan 28 00:17:28 2014 -0600
@@ -55,6 +55,7 @@
         m_nalList[i] = NULL;
     }
 
+    m_blockRefPOC = -1;
     m_nalCount = 0;
     m_totalTime = 0;
     memset(&m_rce, 0, sizeof(RateControlEntry));
@@ -967,9 +968,14 @@
                 for (int ref = 0; ref < slice->getNumRefIdx(l); ref++)
                 {
                     TComPic *refpic = slice->getRefPic(l, ref);
-                    while ((refpic->m_reconRowCount != (uint32_t)m_numRows) && (refpic->m_reconRowCount < row + refLagRows))
+
+                    /* indicate which reference picture we might wait for,
+                     * prior to checking recon row count */
+                    m_blockRefPOC = refpic->getPOC();
+                    while ((refpic->m_reconRowCount != (uint32_t)m_numRows) &&
+                           (refpic->m_reconRowCount < row + refLagRows))
                     {
-                        refpic->m_reconRowWait.wait();
+                        m_reconRowWait.wait();
                     }
 
                     if (slice->getPPS()->getUseWP() && slice->getSliceType() == P_SLICE && m_mref[l][ref].isWeighted)
@@ -1004,9 +1010,14 @@
                     for (int ref = 0; ref < slice->getNumRefIdx(list); ref++)
                     {
                         TComPic *refpic = slice->getRefPic(list, ref);
-                        while ((refpic->m_reconRowCount != (uint32_t)m_numRows) && (refpic->m_reconRowCount < i + refLagRows))
+
+                        /* indicate which reference picture we might wait for,
+                         * prior to checking recon row count */
+                        m_blockRefPOC = refpic->getPOC();
+                        while ((refpic->m_reconRowCount != (uint32_t)m_numRows) &&
+                               (refpic->m_reconRowCount < i + refLagRows))
                         {
-                            refpic->m_reconRowWait.wait();
+                            m_reconRowWait.wait();
                         }
 
                         if (slice->getPPS()->getUseWP() && slice->getSliceType() == P_SLICE && m_mref[l][ref].isWeighted)
diff -r dd0ef09680fe -r 55953908a310 source/encoder/frameencoder.h
--- a/source/encoder/frameencoder.h	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/encoder/frameencoder.h	Tue Jan 28 00:17:28 2014 -0600
@@ -113,6 +113,10 @@
         }
     }
 
+    int          m_blockRefPOC;
+
+    Event        m_reconRowWait;
+
     TEncEntropy* getEntropyCoder(int row)      { return &this->m_rows[row].m_entropyCoder; }
 
     TEncSbac*    getSbacCoder(int row)         { return &this->m_rows[row].m_sbacCoder; }
diff -r dd0ef09680fe -r 55953908a310 source/encoder/framefilter.cpp
--- a/source/encoder/framefilter.cpp	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/encoder/framefilter.cpp	Tue Jan 28 00:17:28 2014 -0600
@@ -61,6 +61,7 @@
 
 void FrameFilter::init(Encoder *top, int numRows, TEncSbac* rdGoOnSbacCoder)
 {
+    m_top = top;
     m_cfg = top;
     m_numRows = numRows;
 
@@ -269,10 +270,8 @@
 
     // Notify other FrameEncoders that this row of reconstructed pixels is available
     m_pic->m_reconRowCount++;
-    for (uint32_t i = 0; i < m_pic->m_countRefEncoders; i++)
-    {
-        m_pic->m_reconRowWait.trigger();
-    }
+    if (m_pic->m_countRefEncoders)
+        m_top->signalReconRowCompleted(m_pic->getPOC());
 
     int cuAddr = lineStartCUAddr;
     if (m_cfg->param.bEnablePsnr)
diff -r dd0ef09680fe -r 55953908a310 source/encoder/framefilter.h
--- a/source/encoder/framefilter.h	Tue Jan 28 07:44:07 2014 +0530
+++ b/source/encoder/framefilter.h	Tue Jan 28 00:17:28 2014 -0600
@@ -56,6 +56,7 @@
 
 protected:
 
+    Encoder*                    m_top;
     TEncCfg*                    m_cfg;
     TComPic*                    m_pic;
 


More information about the x265-devel mailing list