<div dir="ltr">Min,<br><div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Sep 16, 2013 at 5:04 PM, Min Chen <span dir="ltr"><<a href="mailto:chenm003@163.com" target="_blank">chenm003@163.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div># HG changeset patch<br>
# User Min Chen <<a href="mailto:chenm003@163.com" target="_blank">chenm003@163.com</a>><br>
</div># Date 1379324742 -28800<br>
# Node ID 3cae8b54f7e7139ec0502d44fef8088280826a25<br>
# Parent  5a00b5a430d138ed4f77d008d36f037aa8536a6d<br>
<div>Use mixed bitmap between FrameEncoder and FrameFilter to Fix crash and hash mistake in WPP mode<br>
<br></div></blockquote><div><br>Use mixed bitmap between FrameEncoder and FrameFilter to fix crash/hash errors with WPP enabled<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div>
I change task schedult bitmap to mixed FrameEncoder and FrameFilter<br>
because there catch two bugs, and I want to reduce latency of Frame<br>
Parallelism.<br>
The new bitmap mapping 2N+0 to FrameEncoder and 2N+1 to FrameFilter.<br>
<br></div></blockquote><div>Change the task scheduling bitmap to alternate between FrameEncoder and FrameFilter. <br></div><div>This avoids 2 bugs (described below), and reduces the latency with multiple frames encoded in parallel. <br>

</div><div>The new bitmap maps the 2Nth thread to FrameEncoder and the 2N+1-th thread to FrameFilter.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
Side effect:<br>
1. We can remove the lock from FrameFilter.<br>
2. Mixed bitmap let us do Filter early, so reduce latency of Frame<br>
   Parallelism<br>
<br></div></blockquote><div><br></div><div>Mixed bitmap lets us execute filter early, reducing latency of frame parallelism. <br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
Solved bugs:<br>
1. CRASH: the reason is sometime two of threads finish in same time,<br>
   so they will enter Filter in wrong order and sent Finished Event<br>
   early.<br>
   when main thread dequeue JobProvider and execute FrameFilter, we<br>
   will catch a crash!<br></div></blockquote><div><br>Two threads could finish simultanously,  but execute filter in the wrong order and <br></div><div>send a finished Event at the end of the frame early. <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
<br>
2. HASH MISTAKE: the reason is same as below, but last row is right<br>
</div><div>   order, we will got worng reconst image.<br>
<br></div></blockquote><div><br>Out-of-order execution of filter, but the last row finishes in order, so a crash is avoided.<br></div><div>But the recon image is obviously incorrect. <br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
</div>diff -r 5a00b5a430d1 -r 3cae8b54f7e7 source/encoder/frameencoder.cpp<br>
--- a/source/encoder/frameencoder.cpp   Mon Sep 16 17:41:02 2013 +0800<br>
+++ b/source/encoder/frameencoder.cpp   Mon Sep 16 17:45:42 2013 +0800<br>
<div>@@ -98,7 +98,8 @@<br>
         m_rows[i].create(top);<br>
     }<br>
<br>
-    if (!WaveFront::init(m_numRows))<br>
+    // NOTE: 2 times of numRows because both Encoder and Filter in same queue<br>
+    if (!WaveFront::init(m_numRows * 2))<br>
     {<br>
</div>         assert(!"Unable to initialize job queue.");<br>
<div>         m_pool = NULL;<br>
@@ -870,9 +871,9 @@<br>
                 }<br>
             }<br>
<br>
-            WaveFront::enableRow(row);<br>
+            enableRowEncoder(row);<br>
             if (row == 0)<br>
-                WaveFront::enqueueRow(row);<br>
+                enqueueRowEncoder(0);<br>
</div>             else<br>
                 m_pool->pokeIdleThread();<br>
         }<br>
@@ -883,31 +884,43 @@<br>
<div>     }<br>
     else<br>
     {<br>
-        for (int i = 0; i < this->m_numRows; i++)<br>
</div>+        for (int i = 0; i < this->m_numRows + m_filterRowDelay; i++)<br>
         {<br>
-            // block until all reference frames have reconstructed the rows we need<br>
-            for (int l = 0; l < numPredDir; l++)<br>
+            // Encoder<br>
+            if (i < m_numRows)<br>
             {<br>
-                RefPicList list = (l ? REF_PIC_LIST_1 : REF_PIC_LIST_0);<br>
-                for (int ref = 0; ref < slice->getNumRefIdx(list); ref++)<br>
+                // block until all reference frames have reconstructed the rows we need<br>
+                for (int l = 0; l < numPredDir; l++)<br>
                 {<br>
-                    TComPic *refpic = slice->getRefPic(list, ref);<br>
-                    while ((refpic->m_reconRowCount != (UInt)m_numRows) && (refpic->m_reconRowCount < i + refLagRows))<br>
+                    RefPicList list = (l ? REF_PIC_LIST_1 : REF_PIC_LIST_0);<br>
+                    for (int ref = 0; ref < slice->getNumRefIdx(list); ref++)<br>
                     {<br>
-                        refpic->m_reconRowWait.wait();<br>
+                        TComPic *refpic = slice->getRefPic(list, ref);<br>
+                        while ((refpic->m_reconRowCount != (UInt)m_numRows) && (refpic->m_reconRowCount < i + refLagRows))<br>
+                        {<br>
+                            refpic->m_reconRowWait.wait();<br>
+                        }<br>
                     }<br>
                 }<br>
+<br>
+                processRow(i * 2 + 0);<br>
             }<br>
<br>
-            processRow(i);<br>
+            // Filter<br>
+            if (i >= m_filterRowDelay)<br>
+            {<br>
+                processRow((i - m_filterRowDelay) * 2 + 1);<br>
+            }<br>
         }<br>
     }<br>
 }<br>
<br>
<div>-void FrameEncoder::processRow(int row)<br>
+void FrameEncoder::processRowEncoder(int row)<br>
 {<br>
     PPAScopeEvent(Thread_ProcessRow);<br>
<br>
+    //printf("Encoder(%2d)\n", row);<br>
+<br>
     // Called by worker threads<br>
     CTURow& curRow  = m_rows[row];<br>
     CTURow& codeRow = m_rows[m_cfg->param.bEnableWavefront ? row : 0];<br>
</div>@@ -941,7 +954,7 @@<br>
<div>                 m_rows[row + 1].m_completed + 2 <= m_rows[row].m_completed)<br>
             {<br>
                 m_rows[row + 1].m_active = true;<br>
-                WaveFront::enqueueRow(row + 1);<br>
+                enqueueRowEncoder(row + 1);<br>
             }<br>
         }<br>
<br>
</div>@@ -957,13 +970,16 @@<br>
<div>     // Run row-wise loop filters<br>
     if (row >= m_filterRowDelay)<br>
     {<br>
-        m_frameFilter.processRow(row - m_filterRowDelay);<br>
+        enqueueRowFilter(row - m_filterRowDelay);<br>
+<br>
+        // NOTE: Active Filter to first row (row 0)<br>
+        if (row == m_filterRowDelay)<br>
+            enableRowFilter(0);<br>
     }<br>
     if (row == m_numRows - 1)<br>
     {<br>
         for(int i = m_numRows - m_filterRowDelay; i < m_numRows; i++)<br>
-            m_frameFilter.processRow(i);<br>
-        m_completionEvent.trigger();<br>
+            enqueueRowFilter(i);<br>
     }<br>
 }<br>
<br>
</div>diff -r 5a00b5a430d1 -r 3cae8b54f7e7 source/encoder/frameencoder.h<br>
--- a/source/encoder/frameencoder.h     Mon Sep 16 17:41:02 2013 +0800<br>
+++ b/source/encoder/frameencoder.h     Mon Sep 16 17:45:42 2013 +0800<br>
<div>@@ -64,7 +64,54 @@<br>
<br>
     void destroy();<br>
<br>
-    void processRow(int row);<br>
+    void processRowEncoder(int row);<br>
+<br>
</div>+    void processRowFilter(int row)<br>
<div>+    {<br>
+        m_frameFilter.processRow(row);<br>
+    }<br>
+<br>
+    void enqueueRowEncoder(int row)<br>
+    {<br>
+        WaveFront::enqueueRow(row * 2 + 0);<br>
+    }<br>
+<br>
+    void enqueueRowFilter(int row)<br>
+    {<br>
+        WaveFront::enqueueRow(row * 2 + 1);<br>
+    }<br>
+<br>
+    void enableRowEncoder(int row)<br>
+    {<br>
+        WaveFront::enableRow(row * 2 + 0);<br>
+    }<br>
</div><div><div>+<br>
+    void enableRowFilter(int row)<br>
+    {<br>
+        WaveFront::enableRow(row * 2 + 1);<br>
+    }<br>
+<br>
+    void processRow(int row)<br>
+    {<br>
+        const int realRow = row >> 1;<br>
+        const int typeNum = row & 1;<br>
+<br>
+        // TODO: use switch when more type<br>
+        if (typeNum == 0)<br>
+        {<br>
+            processRowEncoder(realRow);<br>
+        }<br>
+        else<br>
+        {<br>
+            processRowFilter(realRow);<br>
+<br>
+            // NOTE: Active next row<br>
+            if (realRow != m_numRows - 1)<br>
+                enableRowFilter(realRow + 1);<br>
+            else<br>
+                m_completionEvent.trigger();<br>
+        }<br>
+    }<br>
<br>
</div></div><div>     TEncEntropy* getEntropyCoder(int row)      { return &this->m_rows[row].m_entropyCoder; }<br>
<br>
</div>diff -r 5a00b5a430d1 -r 3cae8b54f7e7 source/encoder/framefilter.cpp<br>
--- a/source/encoder/framefilter.cpp    Mon Sep 16 17:41:02 2013 +0800<br>
+++ b/source/encoder/framefilter.cpp    Mon Sep 16 17:45:42 2013 +0800<br>
<div>@@ -102,8 +102,6 @@<br>
 {<br>
     PPAScopeEvent(Thread_filterCU);<br>
<br>
-    ScopedLock s(m_filterLock); // Only allow one row to be filtered at a time<br>
-<br>
     if (!m_cfg->param.bEnableLoopFilter)<br>
     {<br>
</div>         processRowPost(row);<br>
diff -r 5a00b5a430d1 -r 3cae8b54f7e7 source/encoder/framefilter.h<br>
--- a/source/encoder/framefilter.h      Mon Sep 16 17:41:02 2013 +0800<br>
+++ b/source/encoder/framefilter.h      Mon Sep 16 17:45:42 2013 +0800<br>
<div><div>@@ -70,8 +70,6 @@<br>
     TEncBinCABACCounter         m_rdGoOnBinCodersCABAC;<br>
     TComBitCounter              m_bitCounter;<br>
     TEncSbac*                   m_rdGoOnSbacCoderRow0;  // for bitstream exact only, depends on HM's bug<br>
-<br>
-    Lock                        m_filterLock;<br>
 };<br>
 }<br>
<br>
<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</div></div></blockquote></div><br></div></div><div id="__tbSetup"></div></div>