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/SingleLock.h"
30 #include "utils/log.h"
31 #include "utils/TimeUtils.h"
33 #include "Application.h"
34 #include "ApplicationMessenger.h"
35 #include "settings/AdvancedSettings.h"
36 #include "settings/MediaSettings.h"
37 #include "settings/Settings.h"
40 #include "LinuxRendererGL.h"
42 #include "LinuxRendererGLES.h"
44 #include "WinRenderer.h"
45 #elif defined(HAS_SDL)
46 #include "LinuxRenderer.h"
49 #include "RenderCapture.h"
51 /* to use the same as player */
52 #include "../dvdplayer/DVDClock.h"
53 #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
54 #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h"
56 #define MAXPRESENTDELAY 0.500
58 /* at any point we want an exclusive lock on rendermanager */
59 /* we must make sure we don't have a graphiccontext lock */
60 /* these two functions allow us to step out from that lock */
61 /* and reaquire it after having the exclusive lock */
67 CRetakeLock(CSharedSection §ion, CCriticalSection &owned = g_graphicsContext)
68 : m_count(owned.exit())
72 m_owned.restore(m_count);
75 void Leave() { m_lock.Leave(); }
78 m_count = m_owned.exit();
80 m_owned.restore(m_count);
86 CCriticalSection &m_owned;
89 static void requeue(std::deque<int> &trg, std::deque<int> &src)
91 trg.push_back(src.front());
95 CXBMCRenderManager::CXBMCRenderManager()
100 m_presentstep = PRESENT_IDLE;
103 m_bReconfigured = false;
104 m_hasCaptures = false;
105 m_displayLatency = 0.0f;
108 memset(&m_errorbuff, 0, ERRORBUFFSIZE);
112 m_format = RENDER_FMT_NONE;
115 CXBMCRenderManager::~CXBMCRenderManager()
121 void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
123 CSharedLock lock(m_sharedSection);
125 m_pRenderer->GetVideoRect(source, dest);
128 float CXBMCRenderManager::GetAspectRatio()
130 CSharedLock lock(m_sharedSection);
132 return m_pRenderer->GetAspectRatio();
137 /* These is based on CurrentHostCounter() */
138 double CXBMCRenderManager::GetPresentTime()
140 return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
143 static double wrap(double x, double minimum, double maximum)
148 x = fmod(x - minimum, maximum - minimum) + minimum;
150 x += maximum - minimum;
152 x -= maximum - minimum;
156 void CXBMCRenderManager::WaitPresentTime(double presenttime)
159 int fps = g_VideoReferenceClock.GetRefreshRate(&frametime);
162 /* smooth video not enabled */
163 CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE);
167 bool ismaster = CDVDClock::IsMasterClock();
169 //the videoreferenceclock updates its clock on every vertical blank
170 //we want every frame's presenttime to end up in the middle of two vblanks
171 //if CDVDPlayerAudio is the master clock, we add a correction to the presenttime
173 presenttime += m_presentcorr * frametime;
175 double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE;
177 double error = ( clock - presenttime ) / frametime - target;
179 m_presenterr = error;
181 // correct error so it targets the closest vblank
182 error = wrap(error, 0.0 - target, 1.0 - target);
184 // scale the error used for correction,
185 // based on how much buffer we have on
186 // that side of the target
188 error /= 2.0 * (1.0 - target);
190 error /= 2.0 * (0.0 + target);
192 //save error in the buffer
193 m_errorindex = (m_errorindex + 1) % ERRORBUFFSIZE;
194 m_errorbuff[m_errorindex] = error;
196 //get the average error from the buffer
197 double avgerror = 0.0;
198 for (int i = 0; i < ERRORBUFFSIZE; i++)
199 avgerror += m_errorbuff[i];
201 avgerror /= ERRORBUFFSIZE;
204 //if CDVDPlayerAudio is not the master clock, we change the clock speed slightly
205 //to make every frame's presenttime end up in the middle of two vblanks
208 //integral correction, clamp to -0.5:0.5 range
209 m_presentcorr = std::max(std::min(m_presentcorr + avgerror * 0.01, 0.1), -0.1);
210 g_VideoReferenceClock.SetFineAdjust(1.0 - avgerror * 0.01 - m_presentcorr * 0.01);
214 //integral correction, wrap to -0.5:0.5 range
215 m_presentcorr = wrap(m_presentcorr + avgerror * 0.01, target - 1.0, target);
216 g_VideoReferenceClock.SetFineAdjust(1.0);
219 //printf("%f %f % 2.0f%% % f % f\n", presenttime, clock, m_presentcorr * 100, error, error_org);
222 CStdString CXBMCRenderManager::GetVSyncState()
224 double avgerror = 0.0;
225 for (int i = 0; i < ERRORBUFFSIZE; i++)
226 avgerror += m_errorbuff[i];
227 avgerror /= ERRORBUFFSIZE;
230 state.Format("sync:%+3d%% avg:%3d%% error:%2d%%"
231 , MathUtils::round_int(m_presentcorr * 100)
232 , MathUtils::round_int(avgerror * 100)
233 , abs(MathUtils::round_int(m_presenterr * 100)));
237 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)
240 CSingleLock lock2(m_presentlock);
242 /* make sure any queued frame was fully presented */
243 XbmcThreads::EndTime endtime(5000);
244 while(m_presentstep != PRESENT_IDLE)
246 if(endtime.IsTimePast())
248 CLog::Log(LOGWARNING, "CRenderManager::Configure - timeout waiting for state");
251 m_presentevent.wait(lock2, endtime.MillisLeft());
255 CExclusiveLock lock(m_sharedSection);
258 CLog::Log(LOGERROR, "%s called without a valid Renderer object", __FUNCTION__);
263 bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
266 if( flags & CONF_FLAGS_FULLSCREEN )
269 CApplicationMessenger::Get().SwitchToFullscreen();
275 int processor = m_pRenderer->GetProcessorSize();
277 m_QueueSize = buffers - processor + 1; /* respect maximum refs */
279 m_QueueSize = m_pRenderer->GetMaxBufferSize(); /* no refs to data */
281 m_QueueSize = std::min(m_QueueSize, (int)m_pRenderer->GetMaxBufferSize());
282 m_QueueSize = std::min(m_QueueSize, NUM_BUFFERS);
286 CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, processor, buffers);
289 m_pRenderer->SetBufferSize(m_QueueSize);
290 m_pRenderer->Update();
296 for (int i=1; i < m_QueueSize; i++)
300 m_bReconfigured = true;
301 m_presentstep = PRESENT_IDLE;
302 m_presentevent.notifyAll();
304 m_firstFlipPage = false; // tempfix
306 CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize);
312 bool CXBMCRenderManager::RendererHandlesPresent() const
314 return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
317 bool CXBMCRenderManager::IsConfigured() const
321 return m_pRenderer->IsConfigured();
324 void CXBMCRenderManager::Update()
326 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
329 m_pRenderer->Update();
332 bool CXBMCRenderManager::FrameWait(int ms)
334 XbmcThreads::EndTime timeout(ms);
335 CSingleLock lock(m_presentlock);
336 while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast())
337 m_presentevent.wait(lock, timeout.MillisLeft());
338 return m_presentstep != PRESENT_IDLE;
341 void CXBMCRenderManager::FrameMove()
343 { CSharedLock lock(m_sharedSection);
344 CSingleLock lock2(m_presentlock);
349 if (m_presentstep == PRESENT_FRAME2)
351 if(!m_queued.empty())
353 double timestamp = GetPresentTime();
354 SPresent& m = m_Queue[m_presentsource];
355 SPresent& q = m_Queue[m_queued.front()];
356 if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
358 m_presentstep = PRESENT_READY;
359 m_presentevent.notifyAll();
364 if (m_presentstep == PRESENT_READY)
367 if(m_presentstep == PRESENT_FLIP)
369 m_pRenderer->FlipPage(m_presentsource);
370 m_presentstep = PRESENT_FRAME;
371 m_presentevent.notifyAll();
374 /* release all previous */
375 for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
377 // TODO check for fence
378 m_pRenderer->ReleaseBuffer(*it);
379 m_overlays.Release(*it);
380 m_free.push_back(*it);
381 it = m_discard.erase(it);
386 void CXBMCRenderManager::FrameFinish()
388 /* wait for this present to be valid */
389 SPresent& m = m_Queue[m_presentsource];
391 if(g_graphicsContext.IsFullScreenVideo())
392 WaitPresentTime(m.timestamp);
394 { CSingleLock lock(m_presentlock);
396 if(m_presentstep == PRESENT_FRAME)
398 if( m.presentmethod == PRESENT_METHOD_BOB
399 || m.presentmethod == PRESENT_METHOD_WEAVE)
400 m_presentstep = PRESENT_FRAME2;
402 m_presentstep = PRESENT_IDLE;
404 else if(m_presentstep == PRESENT_FRAME2)
405 m_presentstep = PRESENT_IDLE;
408 if(m_presentstep == PRESENT_IDLE)
410 if(!m_queued.empty())
411 m_presentstep = PRESENT_READY;
414 m_presentevent.notifyAll();
418 unsigned int CXBMCRenderManager::PreInit()
420 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
425 memset(m_errorbuff, 0, sizeof(m_errorbuff));
427 m_bIsStarted = false;
431 m_pRenderer = new CLinuxRendererGL();
433 m_pRenderer = new CLinuxRendererGLES();
434 #elif defined(HAS_DX)
435 m_pRenderer = new CWinRenderer();
436 #elif defined(HAS_SDL)
437 m_pRenderer = new CLinuxRenderer();
441 UpdateDisplayLatency();
446 return m_pRenderer->PreInit();
449 void CXBMCRenderManager::UnInit()
451 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
453 m_bIsStarted = false;
457 // free renderer resources.
458 // TODO: we may also want to release the renderer here.
460 m_pRenderer->UnInit();
463 bool CXBMCRenderManager::Flush()
468 if (g_application.IsCurrentThread())
470 CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
472 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
473 m_pRenderer->Flush();
479 ThreadMessage msg = {TMSG_RENDERER_FLUSH};
480 m_flushEvent.Reset();
481 CApplicationMessenger::Get().SendMessage(msg, false);
482 if (!m_flushEvent.WaitMSec(1000))
484 CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
493 void CXBMCRenderManager::SetupScreenshot()
495 CSharedLock lock(m_sharedSection);
497 m_pRenderer->SetupScreenshot();
500 CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
502 return new CRenderCapture;
505 void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
507 CSingleLock lock(m_captCritSect);
509 RemoveCapture(capture);
511 //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
512 if (g_application.IsCurrentThread())
518 capture->SetState(CAPTURESTATE_NEEDSDELETE);
519 m_captures.push_back(capture);
522 if (!m_captures.empty())
523 m_hasCaptures = true;
526 void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
528 CSingleLock lock(m_captCritSect);
530 RemoveCapture(capture);
532 capture->SetState(CAPTURESTATE_NEEDSRENDER);
533 capture->SetUserState(CAPTURESTATE_WORKING);
534 capture->SetWidth(width);
535 capture->SetHeight(height);
536 capture->SetFlags(flags);
537 capture->GetEvent().Reset();
539 if (g_application.IsCurrentThread())
541 if (flags & CAPTUREFLAG_IMMEDIATELY)
543 //render capture and read out immediately
544 RenderCapture(capture);
545 capture->SetUserState(capture->GetState());
546 capture->GetEvent().Set();
549 if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
551 //schedule this capture for a render and readout
552 m_captures.push_back(capture);
557 //schedule this capture for a render and readout
558 m_captures.push_back(capture);
561 if (!m_captures.empty())
562 m_hasCaptures = true;
565 void CXBMCRenderManager::ManageCaptures()
567 //no captures, return here so we don't do an unnecessary lock
571 CSingleLock lock(m_captCritSect);
573 std::list<CRenderCapture*>::iterator it = m_captures.begin();
574 while (it != m_captures.end())
576 CRenderCapture* capture = *it;
578 if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
581 it = m_captures.erase(it);
585 if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
586 RenderCapture(capture);
587 else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
590 if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
592 //tell the thread that the capture is done or has failed
593 capture->SetUserState(capture->GetState());
594 capture->GetEvent().Set();
596 if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
598 capture->SetState(CAPTURESTATE_NEEDSRENDER);
600 //if rendering this capture continuously, and readout is async, render a new capture immediately
601 if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
602 RenderCapture(capture);
608 it = m_captures.erase(it);
617 if (m_captures.empty())
618 m_hasCaptures = false;
621 void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
623 CSharedLock lock(m_sharedSection);
624 if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
625 capture->SetState(CAPTURESTATE_FAILED);
628 void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
630 //remove this CRenderCapture from the list
631 std::list<CRenderCapture*>::iterator it;
632 while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
633 m_captures.erase(it);
636 void CXBMCRenderManager::SetViewMode(int iViewMode)
638 CSharedLock lock(m_sharedSection);
640 m_pRenderer->SetViewMode(iViewMode);
643 void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
645 { CSharedLock lock(m_sharedSection);
650 if(!m_pRenderer) return;
652 m_firstFlipPage = true; // tempfix
654 EPRESENTMETHOD presentmethod;
656 EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
657 EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
659 if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
660 deinterlacemode = VS_DEINTERLACEMODE_OFF;
662 if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
663 presentmethod = PRESENT_METHOD_SINGLE;
666 if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
667 presentmethod = PRESENT_METHOD_SINGLE;
671 if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
672 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
673 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
674 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
675 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
676 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
677 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
678 else presentmethod = PRESENT_METHOD_SINGLE;
680 /* default to odd field if we want to deinterlace and don't know better */
681 if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
684 /* invert present field */
695 /* failsafe for invalid timestamps, to make sure queue always empties */
696 if(timestamp > GetPresentTime() + 5.0)
697 timestamp = GetPresentTime() + 5.0;
699 CSingleLock lock2(m_presentlock);
705 source = m_free.front();
707 SPresent& m = m_Queue[source];
708 m.timestamp = timestamp;
709 m.presentfield = sync;
710 m.presentmethod = presentmethod;
711 requeue(m_queued, m_free);
713 /* signal to any waiters to check state */
714 if(m_presentstep == PRESENT_IDLE)
716 m_presentstep = PRESENT_READY;
717 m_presentevent.notifyAll();
722 void CXBMCRenderManager::Reset()
724 CSharedLock lock(m_sharedSection);
726 m_pRenderer->Reset();
729 RESOLUTION CXBMCRenderManager::GetResolution()
731 CSharedLock lock(m_sharedSection);
733 return m_pRenderer->GetResolution();
738 float CXBMCRenderManager::GetMaximumFPS()
742 if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
744 fps = (float)g_VideoReferenceClock.GetRefreshRate();
745 if (fps <= 0) fps = g_graphicsContext.GetFPS();
753 void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
756 m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
759 void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
762 m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
765 void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
767 CSharedLock lock(m_sharedSection);
769 SPresent& m = m_Queue[m_presentsource];
771 if( m.presentmethod == PRESENT_METHOD_BOB )
772 PresentFields(clear, flags, alpha);
773 else if( m.presentmethod == PRESENT_METHOD_WEAVE )
774 PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
775 else if( m.presentmethod == PRESENT_METHOD_BLEND )
776 PresentBlend(clear, flags, alpha);
778 PresentSingle(clear, flags, alpha);
780 m_overlays.Render(m_presentsource);
783 /* simple present method */
784 void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
786 CSingleLock lock(g_graphicsContext);
788 m_pRenderer->RenderUpdate(clear, flags, alpha);
791 /* new simpler method of handling interlaced material, *
792 * we just render the two fields right after eachother */
793 void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
795 CSingleLock lock(g_graphicsContext);
796 SPresent& m = m_Queue[m_presentsource];
798 if(m_presentstep == PRESENT_FRAME)
800 if( m.presentfield == FS_BOT)
801 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
803 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
807 if( m.presentfield == FS_TOP)
808 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
810 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
814 void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
816 CSingleLock lock(g_graphicsContext);
817 SPresent& m = m_Queue[m_presentsource];
819 if( m.presentfield == FS_BOT )
821 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
822 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
826 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
827 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
831 void CXBMCRenderManager::Recover()
833 #if defined(HAS_GL) && !defined(TARGET_DARWIN)
834 glFlush(); // attempt to have gpu done with pixmap and vdpau
837 UpdateDisplayLatency();
840 void CXBMCRenderManager::UpdateDisplayLatency()
842 float refresh = g_graphicsContext.GetFPS();
843 if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
844 refresh = 0; // No idea about refresh rate when windowed, just get the default latency
845 m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
846 CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
849 void CXBMCRenderManager::UpdateResolution()
853 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
854 if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
856 RESOLUTION res = GetResolution();
857 g_graphicsContext.SetVideoResolution(res);
859 m_bReconfigured = false;
864 unsigned int CXBMCRenderManager::GetProcessorSize()
866 CSharedLock lock(m_sharedSection);
867 return std::max(4, NUM_BUFFERS);
870 // Supported pixel formats, can be called before configure
871 std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
873 CSharedLock lock(m_sharedSection);
875 return m_pRenderer->SupportedFormats();
876 return std::vector<ERenderFormat>();
879 int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
881 CSharedLock lock(m_sharedSection);
887 CSingleLock lock(m_presentlock);
890 index = m_free.front();
893 if(m_pRenderer->AddVideoPicture(&pic, index))
897 if (m_pRenderer->GetImage(&image, index) < 0)
900 if(pic.format == RENDER_FMT_YUV420P
901 || pic.format == RENDER_FMT_YUV420P10
902 || pic.format == RENDER_FMT_YUV420P16)
904 CDVDCodecUtils::CopyPicture(&image, &pic);
906 else if(pic.format == RENDER_FMT_NV12)
908 CDVDCodecUtils::CopyNV12Picture(&image, &pic);
910 else if(pic.format == RENDER_FMT_YUYV422
911 || pic.format == RENDER_FMT_UYVY422)
913 CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
915 else if(pic.format == RENDER_FMT_DXVA)
917 CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
920 else if(pic.format == RENDER_FMT_VDPAU
921 || pic.format == RENDER_FMT_VDPAU_420)
922 m_pRenderer->AddProcessor(pic.vdpau, index);
924 #ifdef HAVE_LIBOPENMAX
925 else if(pic.format == RENDER_FMT_OMXEGL)
926 m_pRenderer->AddProcessor(pic.openMax, &pic, index);
929 else if(pic.format == RENDER_FMT_CVBREF)
930 m_pRenderer->AddProcessor(pic.cvBufferRef, index);
933 else if(pic.format == RENDER_FMT_VAAPI)
934 m_pRenderer->AddProcessor(*pic.vaapi, index);
936 #ifdef HAS_LIBSTAGEFRIGHT
937 else if(pic.format == RENDER_FMT_EGLIMG)
938 m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
941 m_pRenderer->ReleaseImage(index, false);
946 bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
948 CSharedLock lock(m_sharedSection);
950 return m_pRenderer->Supports(feature);
955 bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
957 CSharedLock lock(m_sharedSection);
959 return m_pRenderer->Supports(method);
964 bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
966 CSharedLock lock(m_sharedSection);
968 return m_pRenderer->Supports(method);
973 bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
975 CSharedLock lock(m_sharedSection);
977 return m_pRenderer->Supports(method);
982 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
984 CSharedLock lock(m_sharedSection);
985 return AutoInterlaceMethodInternal(mInt);
988 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
990 if (mInt == VS_INTERLACEMETHOD_NONE)
991 return VS_INTERLACEMETHOD_NONE;
993 if(!m_pRenderer->Supports(mInt))
994 mInt = VS_INTERLACEMETHOD_AUTO;
996 if (mInt == VS_INTERLACEMETHOD_AUTO)
997 return m_pRenderer->AutoInterlaceMethod();
1002 int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
1004 CSingleLock lock2(m_presentlock);
1006 XbmcThreads::EndTime endtime(timeout);
1007 while(m_free.empty())
1009 m_presentevent.wait(lock2, std::min(50, timeout));
1010 if(endtime.IsTimePast() || bStop)
1012 if (timeout != 0 && !bStop)
1013 CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
1018 // make sure overlay buffer is released, this won't happen on AddOverlay
1019 m_overlays.Release(m_free.front());
1021 // return buffer level
1022 return m_queued.size() + m_discard.size();;
1025 void CXBMCRenderManager::PrepareNextRender()
1027 CSingleLock lock(m_presentlock);
1029 if (m_queued.empty())
1031 CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
1032 m_presentstep = PRESENT_IDLE;
1033 m_presentevent.notifyAll();
1037 double clocktime = GetPresentTime();
1038 double frametime = 1.0 / GetMaximumFPS();
1040 /* see if any future queued frames are already due */
1041 std::deque<int>::reverse_iterator curr, prev;
1043 curr = prev = m_queued.rbegin();
1045 while (prev != m_queued.rend())
1047 if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
1048 && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
1055 /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
1057 if(g_graphicsContext.IsFullScreenVideo())
1058 next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
1060 next = (m_Queue[idx].timestamp <= clocktime + frametime);
1064 /* skip late frames */
1065 while(m_queued.front() != idx)
1067 requeue(m_discard, m_queued);
1071 m_presentstep = PRESENT_FLIP;
1072 m_discard.push_back(m_presentsource);
1073 m_presentsource = idx;
1074 m_queued.pop_front();
1075 m_presentevent.notifyAll();
1079 void CXBMCRenderManager::DiscardBuffer()
1081 CSharedLock lock(m_sharedSection);
1082 CSingleLock lock2(m_presentlock);
1084 while(!m_queued.empty())
1085 requeue(m_discard, m_queued);
1087 if(m_presentstep == PRESENT_READY)
1088 m_presentstep = PRESENT_IDLE;
1089 m_presentevent.notifyAll();