aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRainer Hochecker <fernetmenta@online.de>2013-07-04 06:55:45 -0700
committerRainer Hochecker <fernetmenta@online.de>2013-07-04 06:55:45 -0700
commit9dfe7cbef07864dcd918000b4a7703640fbed429 (patch)
treeecbf5c3d87693ecd51b7f48d30a6d41fb69ff050
parent2be3912c9c08e37ac021a133978e63fbe22e9521 (diff)
parentb263eefd78219d06d096a23ddee9f93c20253aa4 (diff)
Merge pull request #2811 from FernetMenta/erenderbuf
renderer: replace ring buffer logic with queues for free, queued, and discarded buffers
-rw-r--r--xbmc/cores/VideoRenderers/RenderManager.cpp172
-rw-r--r--xbmc/cores/VideoRenderers/RenderManager.h27
2 files changed, 98 insertions, 101 deletions
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index a7788d1b0f..bff4b3c76b 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -86,17 +86,20 @@ private:
CCriticalSection &m_owned;
};
+static void requeue(std::deque<int> &trg, std::deque<int> &src)
+{
+ trg.push_back(src.front());
+ src.pop_front();
+}
+
CXBMCRenderManager::CXBMCRenderManager()
{
m_pRenderer = NULL;
m_bIsStarted = false;
- m_presentfield = FS_NONE;
- m_presenttime = 0;
m_presentstep = PRESENT_IDLE;
m_rendermethod = 0;
m_presentsource = 0;
- m_presentmethod = PRESENT_METHOD_SINGLE;
m_bReconfigured = false;
m_hasCaptures = false;
m_displayLatency = 0.0f;
@@ -105,9 +108,8 @@ CXBMCRenderManager::CXBMCRenderManager()
memset(&m_errorbuff, 0, ERRORBUFFSIZE);
m_errorindex = 0;
m_QueueSize = 2;
- m_QueueRender = 0;
- m_QueueOutput = 0;
m_QueueSkip = 0;
+ m_format = RENDER_FMT_NONE;
}
CXBMCRenderManager::~CXBMCRenderManager()
@@ -268,8 +270,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
lock.Enter();
}
lock2.Enter();
- if( format & RENDER_FMT_BYPASS )
- m_presentmethod = PRESENT_METHOD_BYPASS;
+ m_format = format;
int processor = m_pRenderer->GetProcessorSize();
if(processor)
@@ -287,8 +288,13 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
m_pRenderer->SetBufferSize(m_QueueSize);
m_pRenderer->Update();
- m_QueueRender = 0;
- m_QueueOutput = 0;
+
+ m_queued.clear();
+ m_discard.clear();
+ m_free.clear();
+ m_presentsource = 0;
+ for (int i=1; i < m_QueueSize; i++)
+ m_free.push_back(i);
m_bIsStarted = true;
m_bReconfigured = true;
@@ -303,7 +309,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
bool CXBMCRenderManager::RendererHandlesPresent() const
{
- return IsConfigured() && m_presentmethod != PRESENT_METHOD_BYPASS;
+ return IsConfigured() && m_format != RENDER_FMT_BYPASS;
}
bool CXBMCRenderManager::IsConfigured() const
@@ -340,11 +346,12 @@ void CXBMCRenderManager::FrameMove()
if (m_presentstep == PRESENT_FRAME2)
{
- int idx = GetNextRender();
- if(idx >= 0)
+ if(!m_queued.empty())
{
double timestamp = GetPresentTime();
- if(timestamp > m_presenttime + (m_Queue[idx].timestamp - m_presenttime) * 0.5)
+ SPresent& m = m_Queue[m_presentsource];
+ SPresent& q = m_Queue[m_queued.front()];
+ if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
{
m_presentstep = PRESENT_READY;
m_presentevent.notifyAll();
@@ -357,38 +364,37 @@ void CXBMCRenderManager::FrameMove()
if(m_presentstep == PRESENT_FLIP)
{
- /* release all previous */
- int count = 0;
- while(m_QueueRender != m_presentsource)
- {
- m_pRenderer->ReleaseBuffer(m_QueueRender);
- m_overlays.Release(m_QueueRender);
- m_QueueRender = (m_QueueRender + 1) % m_QueueSize;
- count++;
- }
-
- if(count > 1)
- m_QueueSkip += count - 1;
-
m_pRenderer->FlipPage(m_presentsource);
m_presentstep = PRESENT_FRAME;
m_presentevent.notifyAll();
}
+
+ /* release all previous */
+ for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
+ {
+ // TODO check for fence
+ m_pRenderer->ReleaseBuffer(*it);
+ m_overlays.Release(*it);
+ m_free.push_back(*it);
+ it = m_discard.erase(it);
+ }
}
}
void CXBMCRenderManager::FrameFinish()
{
/* wait for this present to be valid */
+ SPresent& m = m_Queue[m_presentsource];
+
if(g_graphicsContext.IsFullScreenVideo())
- WaitPresentTime(m_presenttime);
+ WaitPresentTime(m.timestamp);
{ CSingleLock lock(m_presentlock);
if(m_presentstep == PRESENT_FRAME)
{
- if( m_presentmethod == PRESENT_METHOD_BOB
- || m_presentmethod == PRESENT_METHOD_WEAVE)
+ if( m.presentmethod == PRESENT_METHOD_BOB
+ || m.presentmethod == PRESENT_METHOD_WEAVE)
m_presentstep = PRESENT_FRAME2;
else
m_presentstep = PRESENT_IDLE;
@@ -399,7 +405,7 @@ void CXBMCRenderManager::FrameFinish()
if(m_presentstep == PRESENT_IDLE)
{
- if(GetNextRender() >= 0)
+ if(!m_queued.empty())
m_presentstep = PRESENT_READY;
}
@@ -433,8 +439,6 @@ unsigned int CXBMCRenderManager::PreInit()
UpdateDisplayLatency();
m_QueueSize = 2;
- m_QueueRender = 0;
- m_QueueOutput = 0;
m_QueueSkip = 0;
return m_pRenderer->PreInit();
@@ -690,13 +694,17 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L
CSingleLock lock2(m_presentlock);
+ if(m_free.empty())
+ return;
+
if(source < 0)
- source = GetNextDecode();
+ source = m_free.front();
- m_Queue[source].timestamp = timestamp;
- m_Queue[source].presentfield = sync;
- m_Queue[source].presentmethod = presentmethod;
- m_QueueOutput = source;
+ SPresent& m = m_Queue[source];
+ m.timestamp = timestamp;
+ m.presentfield = sync;
+ m.presentmethod = presentmethod;
+ requeue(m_queued, m_free);
/* signal to any waiters to check state */
if(m_presentstep == PRESENT_IDLE)
@@ -754,11 +762,13 @@ void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
{
CSharedLock lock(m_sharedSection);
- if( m_presentmethod == PRESENT_METHOD_BOB )
+ SPresent& m = m_Queue[m_presentsource];
+
+ if( m.presentmethod == PRESENT_METHOD_BOB )
PresentFields(clear, flags, alpha);
- else if( m_presentmethod == PRESENT_METHOD_WEAVE )
+ else if( m.presentmethod == PRESENT_METHOD_WEAVE )
PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
- else if( m_presentmethod == PRESENT_METHOD_BLEND )
+ else if( m.presentmethod == PRESENT_METHOD_BLEND )
PresentBlend(clear, flags, alpha);
else
PresentSingle(clear, flags, alpha);
@@ -779,17 +789,18 @@ void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
{
CSingleLock lock(g_graphicsContext);
+ SPresent& m = m_Queue[m_presentsource];
if(m_presentstep == PRESENT_FRAME)
{
- if( m_presentfield == FS_BOT)
+ if( m.presentfield == FS_BOT)
m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
else
m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
}
else
{
- if( m_presentfield == FS_TOP)
+ if( m.presentfield == FS_TOP)
m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
else
m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
@@ -799,8 +810,9 @@ void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
{
CSingleLock lock(g_graphicsContext);
+ SPresent& m = m_Queue[m_presentsource];
- if( m_presentfield == FS_BOT )
+ if( m.presentfield == FS_BOT )
{
m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
@@ -866,9 +878,13 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
if (!m_pRenderer)
return -1;
- int index = GetNextDecode();
- if(index < 0)
- return -1;
+ int index;
+ {
+ CSingleLock lock(m_presentlock);
+ if (m_free.empty())
+ return -1;
+ index = m_free.front();
+ }
if(m_pRenderer->AddVideoPicture(&pic, index))
return 1;
@@ -978,7 +994,7 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
CSingleLock lock2(m_presentlock);
XbmcThreads::EndTime endtime(timeout);
- while(GetNextDecode() < 0)
+ while(m_free.empty())
{
m_presentevent.wait(lock2, std::min(50, timeout));
if(endtime.IsTimePast() || bStop)
@@ -990,34 +1006,17 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
}
// make sure overlay buffer is released, this won't happen on AddOverlay
- m_overlays.Release(GetNextDecode());
+ m_overlays.Release(m_free.front());
// return buffer level
- return (m_QueueOutput - m_QueueRender + m_QueueSize) % m_QueueSize;
-}
-
-int CXBMCRenderManager::GetNextRender()
-{
- if (m_QueueOutput == m_QueueRender)
- return -1;
- return (m_QueueRender + 1) % m_QueueSize;
-}
-
-int CXBMCRenderManager::GetNextDecode()
-{
- int outputPlus1 = (m_QueueOutput + 1) % m_QueueSize;
- if (outputPlus1 == m_QueueRender)
- return -1;
- else
- return outputPlus1;
+ return m_queued.size() + m_discard.size();;
}
void CXBMCRenderManager::PrepareNextRender()
{
CSingleLock lock(m_presentlock);
- int nxt = GetNextRender();
- if (nxt < 0)
+ if (m_queued.empty())
{
CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
m_presentstep = PRESENT_IDLE;
@@ -1029,16 +1028,19 @@ void CXBMCRenderManager::PrepareNextRender()
double frametime = 1.0 / GetMaximumFPS();
/* see if any future queued frames are already due */
- int prv;
- int idx = m_QueueOutput;
- while(idx != nxt)
+ std::deque<int>::reverse_iterator curr, prev;
+ int idx;
+ curr = prev = m_queued.rbegin();
+ ++prev;
+ while (prev != m_queued.rend())
{
- prv = (idx + m_QueueSize - 1) % m_QueueSize;
- if(clocktime > m_Queue[prv].timestamp /* previous frame is late */
- && clocktime > m_Queue[idx].timestamp - frametime) /* selected frame is close to it's display time */
+ if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
+ && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
break;
- idx = prv;
+ ++curr;
+ ++prev;
}
+ idx = *curr;
/* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
bool next;
@@ -1049,11 +1051,17 @@ void CXBMCRenderManager::PrepareNextRender()
if (next)
{
- m_presenttime = m_Queue[idx].timestamp;
- m_presentmethod = m_Queue[idx].presentmethod;
- m_presentfield = m_Queue[idx].presentfield;
+ /* skip late frames */
+ while(m_queued.front() != idx)
+ {
+ requeue(m_discard, m_queued);
+ m_QueueSkip++;
+ }
+
m_presentstep = PRESENT_FLIP;
+ m_discard.push_back(m_presentsource);
m_presentsource = idx;
+ m_queued.pop_front();
m_presentevent.notifyAll();
}
}
@@ -1062,12 +1070,10 @@ void CXBMCRenderManager::DiscardBuffer()
{
CSharedLock lock(m_sharedSection);
CSingleLock lock2(m_presentlock);
- while(m_QueueOutput != m_QueueRender)
- {
- m_pRenderer->ReleaseBuffer(m_QueueOutput);
- m_overlays.Release(m_QueueOutput);
- m_QueueOutput = (m_QueueOutput + m_QueueSize - 1) % m_QueueSize;
- }
+
+ while(!m_queued.empty())
+ requeue(m_discard, m_queued);
+
if(m_presentstep == PRESENT_READY)
m_presentstep = PRESENT_IDLE;
m_presentevent.notifyAll();
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index d947e9e3d6..83dc50ac1c 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -29,6 +29,7 @@
#include "threads/Thread.h"
#include "settings/VideoSettings.h"
#include "OverlayRenderer.h"
+#include <deque>
class CRenderCapture;
@@ -107,7 +108,7 @@ public:
void AddOverlay(CDVDOverlay* o, double pts)
{
CSharedLock lock(m_sharedSection);
- m_overlays.AddOverlay(o, pts, (m_QueueOutput + 1) % m_QueueSize);
+ m_overlays.AddOverlay(o, pts, m_free.front());
}
void AddCleanup(OVERLAY::COverlay* o)
@@ -184,8 +185,6 @@ protected:
void PresentFields(bool clear, DWORD flags, DWORD alpha);
void PresentBlend(bool clear, DWORD flags, DWORD alpha);
- int GetNextRender();
- int GetNextDecode();
void PrepareNextRender();
EINTERLACEMETHOD AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt);
@@ -212,39 +211,31 @@ protected:
PRESENT_METHOD_BLEND,
PRESENT_METHOD_WEAVE,
PRESENT_METHOD_BOB,
- PRESENT_METHOD_BYPASS,
};
double m_displayLatency;
void UpdateDisplayLatency();
- // Render Buffer State Description:
- //
- // Output: is the buffer about to or having its texture prepared for render (ie from output thread).
- // Cannot go past the "Displayed" buffer (otherwise we will probably overwrite buffers not yet
- // displayed or even rendered).
- // Render: is the current buffer being or having been submitted for render to back buffer.
- // Cannot go past "Output" buffer (else it would be rendering old output).
-
- int m_QueueRender;
- int m_QueueOutput;
int m_QueueSize;
int m_QueueSkip;
- struct
+ struct SPresent
{
double timestamp;
EFIELDSYNC presentfield;
EPRESENTMETHOD presentmethod;
} m_Queue[NUM_BUFFERS];
- double m_presenttime;
+ std::deque<int> m_free;
+ std::deque<int> m_queued;
+ std::deque<int> m_discard;
+
+ ERenderFormat m_format;
+
double m_presentcorr;
double m_presenterr;
double m_errorbuff[ERRORBUFFSIZE];
int m_errorindex;
- EFIELDSYNC m_presentfield;
- EPRESENTMETHOD m_presentmethod;
EPRESENTSTEP m_presentstep;
int m_presentsource;
XbmcThreads::ConditionVariable m_presentevent;