diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2013-07-04 06:55:45 -0700 |
---|---|---|
committer | Rainer Hochecker <fernetmenta@online.de> | 2013-07-04 06:55:45 -0700 |
commit | 9dfe7cbef07864dcd918000b4a7703640fbed429 (patch) | |
tree | ecbf5c3d87693ecd51b7f48d30a6d41fb69ff050 | |
parent | 2be3912c9c08e37ac021a133978e63fbe22e9521 (diff) | |
parent | b263eefd78219d06d096a23ddee9f93c20253aa4 (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.cpp | 172 | ||||
-rw-r--r-- | xbmc/cores/VideoRenderers/RenderManager.h | 27 |
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; |