<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>