2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 #include "system_gl.h"
25 #include "RenderManager.h"
26 #include "threads/CriticalSection.h"
27 #include "video/VideoReferenceClock.h"
28 #include "utils/MathUtils.h"
29 #include "threads/Atomics.h"
30 #include "threads/SingleLock.h"
31 #include "utils/log.h"
32 #include "utils/TimeUtils.h"
34 #include "Application.h"
35 #include "ApplicationMessenger.h"
36 #include "settings/AdvancedSettings.h"
37 #include "settings/MediaSettings.h"
38 #include "settings/Settings.h"
41 #include "LinuxRendererGL.h"
43 #include "LinuxRendererGLES.h"
45 #include "WinRenderer.h"
46 #elif defined(HAS_SDL)
47 #include "LinuxRenderer.h"
50 #include "RenderCapture.h"
52 /* to use the same as player */
53 #include "../dvdplayer/DVDClock.h"
54 #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
55 #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h"
57 #define MAXPRESENTDELAY 0.500
59 /* at any point we want an exclusive lock on rendermanager */
60 /* we must make sure we don't have a graphiccontext lock */
61 /* these two functions allow us to step out from that lock */
62 /* and reaquire it after having the exclusive lock */
68 CRetakeLock(CSharedSection §ion, CCriticalSection &owned = g_graphicsContext)
69 : m_count(owned.exit())
73 m_owned.restore(m_count);
76 void Leave() { m_lock.Leave(); }
79 m_count = m_owned.exit();
81 m_owned.restore(m_count);
87 CCriticalSection &m_owned;
90 static void requeue(std::deque<int> &trg, std::deque<int> &src)
92 trg.push_back(src.front());
96 CXBMCRenderManager::CXBMCRenderManager()
101 m_presentstep = PRESENT_IDLE;
104 m_bReconfigured = false;
105 m_hasCaptures = false;
106 m_displayLatency = 0.0f;
109 memset(&m_errorbuff, 0, ERRORBUFFSIZE);
113 m_format = RENDER_FMT_NONE;
116 CXBMCRenderManager::~CXBMCRenderManager()
122 void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
124 CSharedLock lock(m_sharedSection);
126 m_pRenderer->GetVideoRect(source, dest);
129 float CXBMCRenderManager::GetAspectRatio()
131 CSharedLock lock(m_sharedSection);
133 return m_pRenderer->GetAspectRatio();
138 /* These is based on CurrentHostCounter() */
139 double CXBMCRenderManager::GetPresentTime()
141 return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
144 static double wrap(double x, double minimum, double maximum)
149 x = fmod(x - minimum, maximum - minimum) + minimum;
151 x += maximum - minimum;
153 x -= maximum - minimum;
157 void CXBMCRenderManager::WaitPresentTime(double presenttime)
160 int fps = g_VideoReferenceClock.GetRefreshRate(&frametime);
163 /* smooth video not enabled */
164 CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE);
168 bool ismaster = CDVDClock::IsMasterClock();
170 //the videoreferenceclock updates its clock on every vertical blank
171 //we want every frame's presenttime to end up in the middle of two vblanks
172 //if CDVDPlayerAudio is the master clock, we add a correction to the presenttime
174 presenttime += m_presentcorr * frametime;
176 double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE;
178 double error = ( clock - presenttime ) / frametime - target;
180 m_presenterr = error;
182 // correct error so it targets the closest vblank
183 error = wrap(error, 0.0 - target, 1.0 - target);
185 // scale the error used for correction,
186 // based on how much buffer we have on
187 // that side of the target
189 error /= 2.0 * (1.0 - target);
191 error /= 2.0 * (0.0 + target);
193 //save error in the buffer
194 m_errorindex = (m_errorindex + 1) % ERRORBUFFSIZE;
195 m_errorbuff[m_errorindex] = error;
197 //get the average error from the buffer
198 double avgerror = 0.0;
199 for (int i = 0; i < ERRORBUFFSIZE; i++)
200 avgerror += m_errorbuff[i];
202 avgerror /= ERRORBUFFSIZE;
205 //if CDVDPlayerAudio is not the master clock, we change the clock speed slightly
206 //to make every frame's presenttime end up in the middle of two vblanks
209 //integral correction, clamp to -0.5:0.5 range
210 m_presentcorr = std::max(std::min(m_presentcorr + avgerror * 0.01, 0.1), -0.1);
211 g_VideoReferenceClock.SetFineAdjust(1.0 - avgerror * 0.01 - m_presentcorr * 0.01);
215 //integral correction, wrap to -0.5:0.5 range
216 m_presentcorr = wrap(m_presentcorr + avgerror * 0.01, target - 1.0, target);
217 g_VideoReferenceClock.SetFineAdjust(1.0);
220 //printf("%f %f % 2.0f%% % f % f\n", presenttime, clock, m_presentcorr * 100, error, error_org);
223 CStdString CXBMCRenderManager::GetVSyncState()
225 double avgerror = 0.0;
226 for (int i = 0; i < ERRORBUFFSIZE; i++)
227 avgerror += m_errorbuff[i];
228 avgerror /= ERRORBUFFSIZE;
231 state.Format("sync:%+3d%% avg:%3d%% error:%2d%%"
232 , MathUtils::round_int(m_presentcorr * 100)
233 , MathUtils::round_int(avgerror * 100)
234 , abs(MathUtils::round_int(m_presenterr * 100)));
238 bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, int buffers)
241 CSingleLock lock2(m_presentlock);
243 /* make sure any queued frame was fully presented */
244 XbmcThreads::EndTime endtime(5000);
245 while(m_presentstep != PRESENT_IDLE)
247 if(endtime.IsTimePast())
249 CLog::Log(LOGWARNING, "CRenderManager::Configure - timeout waiting for state");
252 m_presentevent.wait(lock2, endtime.MillisLeft());
256 CExclusiveLock lock(m_sharedSection);
259 CLog::Log(LOGERROR, "%s called without a valid Renderer object", __FUNCTION__);
264 bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
267 if( flags & CONF_FLAGS_FULLSCREEN )
270 CApplicationMessenger::Get().SwitchToFullscreen();
276 int processor = m_pRenderer->GetProcessorSize();
278 m_QueueSize = buffers - processor + 1; /* respect maximum refs */
280 m_QueueSize = m_pRenderer->GetMaxBufferSize(); /* no refs to data */
282 m_QueueSize = std::min(m_QueueSize, (int)m_pRenderer->GetMaxBufferSize());
283 m_QueueSize = std::min(m_QueueSize, NUM_BUFFERS);
287 CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, processor, buffers);
290 m_pRenderer->SetBufferSize(m_QueueSize);
291 m_pRenderer->Update();
297 for (int i=1; i < m_QueueSize; i++)
301 m_bReconfigured = true;
302 m_presentstep = PRESENT_IDLE;
303 m_presentevent.notifyAll();
305 m_firstFlipPage = false; // tempfix
307 CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize);
313 bool CXBMCRenderManager::RendererHandlesPresent() const
315 return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
318 bool CXBMCRenderManager::IsConfigured() const
322 return m_pRenderer->IsConfigured();
325 void CXBMCRenderManager::Update()
327 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
330 m_pRenderer->Update();
333 bool CXBMCRenderManager::FrameWait(int ms)
335 XbmcThreads::EndTime timeout(ms);
336 CSingleLock lock(m_presentlock);
337 while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast())
338 m_presentevent.wait(lock, timeout.MillisLeft());
339 return m_presentstep != PRESENT_IDLE;
342 void CXBMCRenderManager::FrameMove()
344 { CSharedLock lock(m_sharedSection);
345 CSingleLock lock2(m_presentlock);
350 if (m_presentstep == PRESENT_FRAME2)
352 if(!m_queued.empty())
354 double timestamp = GetPresentTime();
355 SPresent& m = m_Queue[m_presentsource];
356 SPresent& q = m_Queue[m_queued.front()];
357 if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
359 m_presentstep = PRESENT_READY;
360 m_presentevent.notifyAll();
365 if (m_presentstep == PRESENT_READY)
368 if(m_presentstep == PRESENT_FLIP)
370 m_pRenderer->FlipPage(m_presentsource);
371 m_presentstep = PRESENT_FRAME;
372 m_presentevent.notifyAll();
375 /* release all previous */
376 for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
378 // TODO check for fence
379 m_pRenderer->ReleaseBuffer(*it);
380 m_overlays.Release(*it);
381 m_free.push_back(*it);
382 it = m_discard.erase(it);
387 void CXBMCRenderManager::FrameFinish()
389 /* wait for this present to be valid */
390 SPresent& m = m_Queue[m_presentsource];
392 if(g_graphicsContext.IsFullScreenVideo())
393 WaitPresentTime(m.timestamp);
395 { CSingleLock lock(m_presentlock);
397 if(m_presentstep == PRESENT_FRAME)
399 if( m.presentmethod == PRESENT_METHOD_BOB
400 || m.presentmethod == PRESENT_METHOD_WEAVE)
401 m_presentstep = PRESENT_FRAME2;
403 m_presentstep = PRESENT_IDLE;
405 else if(m_presentstep == PRESENT_FRAME2)
406 m_presentstep = PRESENT_IDLE;
409 if(m_presentstep == PRESENT_IDLE)
411 if(!m_queued.empty())
412 m_presentstep = PRESENT_READY;
415 m_presentevent.notifyAll();
419 unsigned int CXBMCRenderManager::PreInit()
421 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
426 memset(m_errorbuff, 0, sizeof(m_errorbuff));
428 m_bIsStarted = false;
432 m_pRenderer = new CLinuxRendererGL();
434 m_pRenderer = new CLinuxRendererGLES();
435 #elif defined(HAS_DX)
436 m_pRenderer = new CWinRenderer();
437 #elif defined(HAS_SDL)
438 m_pRenderer = new CLinuxRenderer();
442 UpdateDisplayLatency();
447 return m_pRenderer->PreInit();
450 void CXBMCRenderManager::UnInit()
452 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
454 m_bIsStarted = false;
458 // free renderer resources.
459 // TODO: we may also want to release the renderer here.
461 m_pRenderer->UnInit();
464 bool CXBMCRenderManager::Flush()
469 if (g_application.IsCurrentThread())
471 CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
473 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
474 m_pRenderer->Flush();
480 ThreadMessage msg = {TMSG_RENDERER_FLUSH};
481 m_flushEvent.Reset();
482 CApplicationMessenger::Get().SendMessage(msg, false);
483 if (!m_flushEvent.WaitMSec(1000))
485 CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
494 void CXBMCRenderManager::SetupScreenshot()
496 CSharedLock lock(m_sharedSection);
498 m_pRenderer->SetupScreenshot();
501 CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
503 return new CRenderCapture;
506 void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
508 CSingleLock lock(m_captCritSect);
510 RemoveCapture(capture);
512 //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
513 if (g_application.IsCurrentThread())
519 capture->SetState(CAPTURESTATE_NEEDSDELETE);
520 m_captures.push_back(capture);
523 if (!m_captures.empty())
524 m_hasCaptures = true;
527 void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
529 CSingleLock lock(m_captCritSect);
531 RemoveCapture(capture);
533 capture->SetState(CAPTURESTATE_NEEDSRENDER);
534 capture->SetUserState(CAPTURESTATE_WORKING);
535 capture->SetWidth(width);
536 capture->SetHeight(height);
537 capture->SetFlags(flags);
538 capture->GetEvent().Reset();
540 if (g_application.IsCurrentThread())
542 if (flags & CAPTUREFLAG_IMMEDIATELY)
544 //render capture and read out immediately
545 RenderCapture(capture);
546 capture->SetUserState(capture->GetState());
547 capture->GetEvent().Set();
550 if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
552 //schedule this capture for a render and readout
553 m_captures.push_back(capture);
558 //schedule this capture for a render and readout
559 m_captures.push_back(capture);
562 if (!m_captures.empty())
563 m_hasCaptures = true;
566 void CXBMCRenderManager::ManageCaptures()
568 //no captures, return here so we don't do an unnecessary lock
572 CSingleLock lock(m_captCritSect);
574 std::list<CRenderCapture*>::iterator it = m_captures.begin();
575 while (it != m_captures.end())
577 CRenderCapture* capture = *it;
579 if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
582 it = m_captures.erase(it);
586 if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
587 RenderCapture(capture);
588 else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
591 if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
593 //tell the thread that the capture is done or has failed
594 capture->SetUserState(capture->GetState());
595 capture->GetEvent().Set();
597 if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
599 capture->SetState(CAPTURESTATE_NEEDSRENDER);
601 //if rendering this capture continuously, and readout is async, render a new capture immediately
602 if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
603 RenderCapture(capture);
609 it = m_captures.erase(it);
618 if (m_captures.empty())
619 m_hasCaptures = false;
622 void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
624 CSharedLock lock(m_sharedSection);
625 if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
626 capture->SetState(CAPTURESTATE_FAILED);
629 void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
631 //remove this CRenderCapture from the list
632 std::list<CRenderCapture*>::iterator it;
633 while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
634 m_captures.erase(it);
637 void CXBMCRenderManager::SetViewMode(int iViewMode)
639 CSharedLock lock(m_sharedSection);
641 m_pRenderer->SetViewMode(iViewMode);
644 void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
646 { CSharedLock lock(m_sharedSection);
651 if(!m_pRenderer) return;
653 m_firstFlipPage = true; // tempfix
655 EPRESENTMETHOD presentmethod;
657 EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
658 EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
660 if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
661 deinterlacemode = VS_DEINTERLACEMODE_OFF;
663 if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
664 presentmethod = PRESENT_METHOD_SINGLE;
667 if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
668 presentmethod = PRESENT_METHOD_SINGLE;
672 if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
673 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
674 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
675 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
676 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
677 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
678 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
679 else presentmethod = PRESENT_METHOD_SINGLE;
681 /* default to odd field if we want to deinterlace and don't know better */
682 if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
685 /* invert present field */
696 /* failsafe for invalid timestamps, to make sure queue always empties */
697 if(timestamp > GetPresentTime() + 5.0)
698 timestamp = GetPresentTime() + 5.0;
700 CSingleLock lock2(m_presentlock);
706 source = m_free.front();
708 SPresent& m = m_Queue[source];
709 m.timestamp = timestamp;
710 m.presentfield = sync;
711 m.presentmethod = presentmethod;
712 requeue(m_queued, m_free);
714 /* signal to any waiters to check state */
715 if(m_presentstep == PRESENT_IDLE)
717 m_presentstep = PRESENT_READY;
718 m_presentevent.notifyAll();
723 void CXBMCRenderManager::Reset()
725 CSharedLock lock(m_sharedSection);
727 m_pRenderer->Reset();
730 RESOLUTION CXBMCRenderManager::GetResolution()
732 CSharedLock lock(m_sharedSection);
734 return m_pRenderer->GetResolution();
739 float CXBMCRenderManager::GetMaximumFPS()
743 if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
745 fps = (float)g_VideoReferenceClock.GetRefreshRate();
746 if (fps <= 0) fps = g_graphicsContext.GetFPS();
754 void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
757 m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
760 void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
763 m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
766 void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
768 CSharedLock lock(m_sharedSection);
770 SPresent& m = m_Queue[m_presentsource];
772 if( m.presentmethod == PRESENT_METHOD_BOB )
773 PresentFields(clear, flags, alpha);
774 else if( m.presentmethod == PRESENT_METHOD_WEAVE )
775 PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
776 else if( m.presentmethod == PRESENT_METHOD_BLEND )
777 PresentBlend(clear, flags, alpha);
779 PresentSingle(clear, flags, alpha);
781 m_overlays.Render(m_presentsource);
784 /* simple present method */
785 void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
787 CSingleLock lock(g_graphicsContext);
789 m_pRenderer->RenderUpdate(clear, flags, alpha);
792 /* new simpler method of handling interlaced material, *
793 * we just render the two fields right after eachother */
794 void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
796 CSingleLock lock(g_graphicsContext);
797 SPresent& m = m_Queue[m_presentsource];
799 if(m_presentstep == PRESENT_FRAME)
801 if( m.presentfield == FS_BOT)
802 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
804 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
808 if( m.presentfield == FS_TOP)
809 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
811 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
815 void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
817 CSingleLock lock(g_graphicsContext);
818 SPresent& m = m_Queue[m_presentsource];
820 if( m.presentfield == FS_BOT )
822 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
823 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
827 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
828 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
832 void CXBMCRenderManager::Recover()
834 #if defined(HAS_GL) && !defined(TARGET_DARWIN)
835 glFlush(); // attempt to have gpu done with pixmap and vdpau
838 UpdateDisplayLatency();
841 void CXBMCRenderManager::UpdateDisplayLatency()
843 float refresh = g_graphicsContext.GetFPS();
844 if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
845 refresh = 0; // No idea about refresh rate when windowed, just get the default latency
846 m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
847 CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
850 void CXBMCRenderManager::UpdateResolution()
854 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
855 if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
857 RESOLUTION res = GetResolution();
858 g_graphicsContext.SetVideoResolution(res);
860 m_bReconfigured = false;
865 unsigned int CXBMCRenderManager::GetProcessorSize()
867 CSharedLock lock(m_sharedSection);
868 return std::max(4, NUM_BUFFERS);
871 // Supported pixel formats, can be called before configure
872 std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
874 CSharedLock lock(m_sharedSection);
876 return m_pRenderer->SupportedFormats();
877 return std::vector<ERenderFormat>();
880 int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
882 CSharedLock lock(m_sharedSection);
888 CSingleLock lock(m_presentlock);
891 index = m_free.front();
894 if(m_pRenderer->AddVideoPicture(&pic, index))
898 if (m_pRenderer->GetImage(&image, index) < 0)
901 if(pic.format == RENDER_FMT_YUV420P
902 || pic.format == RENDER_FMT_YUV420P10
903 || pic.format == RENDER_FMT_YUV420P16)
905 CDVDCodecUtils::CopyPicture(&image, &pic);
907 else if(pic.format == RENDER_FMT_NV12)
909 CDVDCodecUtils::CopyNV12Picture(&image, &pic);
911 else if(pic.format == RENDER_FMT_YUYV422
912 || pic.format == RENDER_FMT_UYVY422)
914 CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
916 else if(pic.format == RENDER_FMT_DXVA)
918 CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
921 else if(pic.format == RENDER_FMT_VDPAU
922 || pic.format == RENDER_FMT_VDPAU_420)
923 m_pRenderer->AddProcessor(pic.vdpau, index);
925 #ifdef HAVE_LIBOPENMAX
926 else if(pic.format == RENDER_FMT_OMXEGL)
927 m_pRenderer->AddProcessor(pic.openMax, &pic, index);
930 else if(pic.format == RENDER_FMT_CVBREF)
931 m_pRenderer->AddProcessor(pic.cvBufferRef, index);
934 else if(pic.format == RENDER_FMT_VAAPI)
935 m_pRenderer->AddProcessor(*pic.vaapi, index);
937 #ifdef HAS_LIBSTAGEFRIGHT
938 else if(pic.format == RENDER_FMT_EGLIMG)
939 m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
941 #if defined(TARGET_ANDROID)
942 else if(pic.format == RENDER_FMT_MEDIACODEC)
943 m_pRenderer->AddProcessor(pic.mediacodec, index);
946 m_pRenderer->ReleaseImage(index, false);
951 bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
953 CSharedLock lock(m_sharedSection);
955 return m_pRenderer->Supports(feature);
960 bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
962 CSharedLock lock(m_sharedSection);
964 return m_pRenderer->Supports(method);
969 bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
971 CSharedLock lock(m_sharedSection);
973 return m_pRenderer->Supports(method);
978 bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
980 CSharedLock lock(m_sharedSection);
982 return m_pRenderer->Supports(method);
987 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
989 CSharedLock lock(m_sharedSection);
990 return AutoInterlaceMethodInternal(mInt);
993 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
995 if (mInt == VS_INTERLACEMETHOD_NONE)
996 return VS_INTERLACEMETHOD_NONE;
998 if(!m_pRenderer->Supports(mInt))
999 mInt = VS_INTERLACEMETHOD_AUTO;
1001 if (mInt == VS_INTERLACEMETHOD_AUTO)
1002 return m_pRenderer->AutoInterlaceMethod();
1007 int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
1009 CSingleLock lock2(m_presentlock);
1011 XbmcThreads::EndTime endtime(timeout);
1012 while(m_free.empty())
1014 m_presentevent.wait(lock2, std::min(50, timeout));
1015 if(endtime.IsTimePast() || bStop)
1017 if (timeout != 0 && !bStop)
1018 CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
1023 // make sure overlay buffer is released, this won't happen on AddOverlay
1024 m_overlays.Release(m_free.front());
1026 // return buffer level
1027 return m_queued.size() + m_discard.size();;
1030 void CXBMCRenderManager::PrepareNextRender()
1032 CSingleLock lock(m_presentlock);
1034 if (m_queued.empty())
1036 CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
1037 m_presentstep = PRESENT_IDLE;
1038 m_presentevent.notifyAll();
1042 double clocktime = GetPresentTime();
1043 double frametime = 1.0 / GetMaximumFPS();
1045 /* see if any future queued frames are already due */
1046 std::deque<int>::reverse_iterator curr, prev;
1048 curr = prev = m_queued.rbegin();
1050 while (prev != m_queued.rend())
1052 if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
1053 && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
1060 /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
1062 if(g_graphicsContext.IsFullScreenVideo())
1063 next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
1065 next = (m_Queue[idx].timestamp <= clocktime + frametime);
1069 /* skip late frames */
1070 while(m_queued.front() != idx)
1072 requeue(m_discard, m_queued);
1076 m_presentstep = PRESENT_FLIP;
1077 m_discard.push_back(m_presentsource);
1078 m_presentsource = idx;
1079 m_queued.pop_front();
1080 m_presentevent.notifyAll();
1084 void CXBMCRenderManager::DiscardBuffer()
1086 CSharedLock lock(m_sharedSection);
1087 CSingleLock lock2(m_presentlock);
1089 while(!m_queued.empty())
1090 requeue(m_discard, m_queued);
1092 if(m_presentstep == PRESENT_READY)
1093 m_presentstep = PRESENT_IDLE;
1094 m_presentevent.notifyAll();