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"
33 #include "utils/StringUtils.h"
35 #include "Application.h"
36 #include "ApplicationMessenger.h"
37 #include "settings/AdvancedSettings.h"
38 #include "settings/MediaSettings.h"
39 #include "settings/Settings.h"
40 #include "guilib/GUIFontManager.h"
43 #include "LinuxRendererGL.h"
45 #include "LinuxRendererGLES.h"
47 #include "WinRenderer.h"
48 #elif defined(HAS_SDL)
49 #include "LinuxRenderer.h"
52 #include "RenderCapture.h"
54 /* to use the same as player */
55 #include "../dvdplayer/DVDClock.h"
56 #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
57 #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h"
59 #define MAXPRESENTDELAY 0.500
61 /* at any point we want an exclusive lock on rendermanager */
62 /* we must make sure we don't have a graphiccontext lock */
63 /* these two functions allow us to step out from that lock */
64 /* and reaquire it after having the exclusive lock */
70 CRetakeLock(CSharedSection §ion, CCriticalSection &owned = g_graphicsContext)
71 : m_count(owned.exit())
75 m_owned.restore(m_count);
78 void Leave() { m_lock.Leave(); }
81 m_count = m_owned.exit();
83 m_owned.restore(m_count);
89 CCriticalSection &m_owned;
92 static void requeue(std::deque<int> &trg, std::deque<int> &src)
94 trg.push_back(src.front());
98 CXBMCRenderManager::CXBMCRenderManager()
101 m_bIsStarted = false;
103 m_presentstep = PRESENT_IDLE;
106 m_bReconfigured = false;
107 m_hasCaptures = false;
108 m_displayLatency = 0.0f;
111 memset(&m_errorbuff, 0, ERRORBUFFSIZE);
115 m_format = RENDER_FMT_NONE;
118 CXBMCRenderManager::~CXBMCRenderManager()
124 void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
126 CSharedLock lock(m_sharedSection);
128 m_pRenderer->GetVideoRect(source, dest);
131 float CXBMCRenderManager::GetAspectRatio()
133 CSharedLock lock(m_sharedSection);
135 return m_pRenderer->GetAspectRatio();
140 /* These is based on CurrentHostCounter() */
141 double CXBMCRenderManager::GetPresentTime()
143 return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
146 static double wrap(double x, double minimum, double maximum)
151 x = fmod(x - minimum, maximum - minimum) + minimum;
153 x += maximum - minimum;
155 x -= maximum - minimum;
159 void CXBMCRenderManager::WaitPresentTime(double presenttime)
162 int fps = g_VideoReferenceClock.GetRefreshRate(&frametime);
165 /* smooth video not enabled */
166 CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE);
170 double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE;
172 double error = ( clock - presenttime ) / frametime - target;
174 m_presenterr = error;
176 // correct error so it targets the closest vblank
177 error = wrap(error, 0.0 - target, 1.0 - target);
179 // scale the error used for correction,
180 // based on how much buffer we have on
181 // that side of the target
183 error /= 2.0 * (1.0 - target);
185 error /= 2.0 * (0.0 + target);
187 //save error in the buffer
188 m_errorindex = (m_errorindex + 1) % ERRORBUFFSIZE;
189 m_errorbuff[m_errorindex] = error;
191 //get the average error from the buffer
192 double avgerror = 0.0;
193 for (int i = 0; i < ERRORBUFFSIZE; i++)
194 avgerror += m_errorbuff[i];
196 avgerror /= ERRORBUFFSIZE;
199 //we change the clock speed slightly
200 //to make every frame's presenttime end up in the middle of two vblanks
201 //integral correction, clamp to -0.5:0.5 range
202 m_presentcorr = std::max(std::min(m_presentcorr + avgerror * 0.01, 0.1), -0.1);
203 g_VideoReferenceClock.SetFineAdjust(1.0 - avgerror * 0.01 - m_presentcorr * 0.01);
205 //printf("%f %f % 2.0f%% % f % f\n", presenttime, clock, m_presentcorr * 100, error, error_org);
208 CStdString CXBMCRenderManager::GetVSyncState()
210 double avgerror = 0.0;
211 for (int i = 0; i < ERRORBUFFSIZE; i++)
212 avgerror += m_errorbuff[i];
213 avgerror /= ERRORBUFFSIZE;
215 CStdString state = StringUtils::Format("sync:%+3d%% avg:%3d%% error:%2d%%"
216 , MathUtils::round_int(m_presentcorr * 100)
217 , MathUtils::round_int(avgerror * 100)
218 , abs(MathUtils::round_int(m_presenterr * 100)));
222 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)
225 CSingleLock lock2(m_presentlock);
227 /* make sure any queued frame was fully presented */
228 XbmcThreads::EndTime endtime(5000);
229 while(m_presentstep != PRESENT_IDLE)
231 if(endtime.IsTimePast())
233 CLog::Log(LOGWARNING, "CRenderManager::Configure - timeout waiting for state");
236 m_presentevent.wait(lock2, endtime.MillisLeft());
240 CExclusiveLock lock(m_sharedSection);
243 CLog::Log(LOGERROR, "%s called without a valid Renderer object", __FUNCTION__);
248 bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
251 if( flags & CONF_FLAGS_FULLSCREEN )
254 CApplicationMessenger::Get().SwitchToFullscreen();
260 int processor = m_pRenderer->GetProcessorSize();
261 if(processor > buffers) /* DXVA-HD returns processor size 6 */
262 m_QueueSize = 3; /* we need queue size of 3 to get future frames in the processor */
264 m_QueueSize = buffers - processor + 1; /* respect maximum refs */
266 m_QueueSize = m_pRenderer->GetMaxBufferSize(); /* no refs to data */
268 m_QueueSize = std::min(m_QueueSize, (int)m_pRenderer->GetMaxBufferSize());
269 m_QueueSize = std::min(m_QueueSize, NUM_BUFFERS);
273 CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, processor, buffers);
276 m_pRenderer->SetBufferSize(m_QueueSize);
277 m_pRenderer->Update();
283 for (int i=1; i < m_QueueSize; i++)
287 m_bReconfigured = true;
288 m_presentstep = PRESENT_IDLE;
289 m_presentevent.notifyAll();
291 m_firstFlipPage = false; // tempfix
293 CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize);
299 bool CXBMCRenderManager::RendererHandlesPresent() const
301 return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
304 bool CXBMCRenderManager::IsConfigured() const
308 return m_pRenderer->IsConfigured();
311 void CXBMCRenderManager::Update()
313 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
316 m_pRenderer->Update();
319 bool CXBMCRenderManager::FrameWait(int ms)
321 XbmcThreads::EndTime timeout(ms);
322 CSingleLock lock(m_presentlock);
323 while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast())
324 m_presentevent.wait(lock, timeout.MillisLeft());
325 return m_presentstep != PRESENT_IDLE;
328 void CXBMCRenderManager::FrameMove()
330 { CSharedLock lock(m_sharedSection);
331 CSingleLock lock2(m_presentlock);
336 if (m_presentstep == PRESENT_FRAME2)
338 if(!m_queued.empty())
340 double timestamp = GetPresentTime();
341 SPresent& m = m_Queue[m_presentsource];
342 SPresent& q = m_Queue[m_queued.front()];
343 if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
345 m_presentstep = PRESENT_READY;
346 m_presentevent.notifyAll();
351 if (m_presentstep == PRESENT_READY)
354 if(m_presentstep == PRESENT_FLIP)
356 m_pRenderer->FlipPage(m_presentsource);
357 m_presentstep = PRESENT_FRAME;
358 m_presentevent.notifyAll();
361 /* release all previous */
362 for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
364 // TODO check for fence
365 m_pRenderer->ReleaseBuffer(*it);
366 m_overlays.Release(*it);
367 m_free.push_back(*it);
368 it = m_discard.erase(it);
373 void CXBMCRenderManager::FrameFinish()
375 /* wait for this present to be valid */
376 SPresent& m = m_Queue[m_presentsource];
378 if(g_graphicsContext.IsFullScreenVideo())
379 WaitPresentTime(m.timestamp);
381 { CSingleLock lock(m_presentlock);
383 if(m_presentstep == PRESENT_FRAME)
385 if( m.presentmethod == PRESENT_METHOD_BOB
386 || m.presentmethod == PRESENT_METHOD_WEAVE)
387 m_presentstep = PRESENT_FRAME2;
389 m_presentstep = PRESENT_IDLE;
391 else if(m_presentstep == PRESENT_FRAME2)
392 m_presentstep = PRESENT_IDLE;
395 if(m_presentstep == PRESENT_IDLE)
397 if(!m_queued.empty())
398 m_presentstep = PRESENT_READY;
401 m_presentevent.notifyAll();
405 unsigned int CXBMCRenderManager::PreInit()
407 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
412 memset(m_errorbuff, 0, sizeof(m_errorbuff));
414 m_bIsStarted = false;
418 m_pRenderer = new CLinuxRendererGL();
420 m_pRenderer = new CLinuxRendererGLES();
421 #elif defined(HAS_DX)
422 m_pRenderer = new CWinRenderer();
423 #elif defined(HAS_SDL)
424 m_pRenderer = new CLinuxRenderer();
428 UpdateDisplayLatency();
433 return m_pRenderer->PreInit();
436 void CXBMCRenderManager::UnInit()
438 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
440 m_bIsStarted = false;
443 g_fontManager.Unload("__subtitle__");
444 g_fontManager.Unload("__subtitleborder__");
446 // free renderer resources.
447 // TODO: we may also want to release the renderer here.
449 m_pRenderer->UnInit();
452 bool CXBMCRenderManager::Flush()
457 if (g_application.IsCurrentThread())
459 CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
461 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
462 m_pRenderer->Flush();
468 ThreadMessage msg = {TMSG_RENDERER_FLUSH};
469 m_flushEvent.Reset();
470 CApplicationMessenger::Get().SendMessage(msg, false);
471 if (!m_flushEvent.WaitMSec(1000))
473 CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
482 void CXBMCRenderManager::SetupScreenshot()
484 CSharedLock lock(m_sharedSection);
486 m_pRenderer->SetupScreenshot();
489 CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
491 return new CRenderCapture;
494 void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
496 CSingleLock lock(m_captCritSect);
498 RemoveCapture(capture);
500 //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
501 if (g_application.IsCurrentThread())
507 capture->SetState(CAPTURESTATE_NEEDSDELETE);
508 m_captures.push_back(capture);
511 if (!m_captures.empty())
512 m_hasCaptures = true;
515 void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
517 CSingleLock lock(m_captCritSect);
519 RemoveCapture(capture);
521 capture->SetState(CAPTURESTATE_NEEDSRENDER);
522 capture->SetUserState(CAPTURESTATE_WORKING);
523 capture->SetWidth(width);
524 capture->SetHeight(height);
525 capture->SetFlags(flags);
526 capture->GetEvent().Reset();
528 if (g_application.IsCurrentThread())
530 if (flags & CAPTUREFLAG_IMMEDIATELY)
532 //render capture and read out immediately
533 RenderCapture(capture);
534 capture->SetUserState(capture->GetState());
535 capture->GetEvent().Set();
538 if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
540 //schedule this capture for a render and readout
541 m_captures.push_back(capture);
546 //schedule this capture for a render and readout
547 m_captures.push_back(capture);
550 if (!m_captures.empty())
551 m_hasCaptures = true;
554 void CXBMCRenderManager::ManageCaptures()
556 //no captures, return here so we don't do an unnecessary lock
560 CSingleLock lock(m_captCritSect);
562 std::list<CRenderCapture*>::iterator it = m_captures.begin();
563 while (it != m_captures.end())
565 CRenderCapture* capture = *it;
567 if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
570 it = m_captures.erase(it);
574 if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
575 RenderCapture(capture);
576 else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
579 if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
581 //tell the thread that the capture is done or has failed
582 capture->SetUserState(capture->GetState());
583 capture->GetEvent().Set();
585 if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
587 capture->SetState(CAPTURESTATE_NEEDSRENDER);
589 //if rendering this capture continuously, and readout is async, render a new capture immediately
590 if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
591 RenderCapture(capture);
597 it = m_captures.erase(it);
606 if (m_captures.empty())
607 m_hasCaptures = false;
610 void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
612 CSharedLock lock(m_sharedSection);
613 if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
614 capture->SetState(CAPTURESTATE_FAILED);
617 void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
619 //remove this CRenderCapture from the list
620 std::list<CRenderCapture*>::iterator it;
621 while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
622 m_captures.erase(it);
625 void CXBMCRenderManager::SetViewMode(int iViewMode)
627 CSharedLock lock(m_sharedSection);
629 m_pRenderer->SetViewMode(iViewMode);
632 void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
634 { CSharedLock lock(m_sharedSection);
639 if(!m_pRenderer) return;
641 m_firstFlipPage = true; // tempfix
643 EPRESENTMETHOD presentmethod;
645 EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
646 EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
648 if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
649 deinterlacemode = VS_DEINTERLACEMODE_OFF;
651 if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
652 presentmethod = PRESENT_METHOD_SINGLE;
655 if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
656 presentmethod = PRESENT_METHOD_SINGLE;
660 if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
661 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
662 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
663 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
664 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
665 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
666 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
667 else presentmethod = PRESENT_METHOD_SINGLE;
669 /* default to odd field if we want to deinterlace and don't know better */
670 if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
673 /* invert present field */
684 /* failsafe for invalid timestamps, to make sure queue always empties */
685 if(timestamp > GetPresentTime() + 5.0)
686 timestamp = GetPresentTime() + 5.0;
688 CSingleLock lock2(m_presentlock);
694 source = m_free.front();
696 SPresent& m = m_Queue[source];
697 m.timestamp = timestamp;
698 m.presentfield = sync;
699 m.presentmethod = presentmethod;
700 requeue(m_queued, m_free);
702 /* signal to any waiters to check state */
703 if(m_presentstep == PRESENT_IDLE)
705 m_presentstep = PRESENT_READY;
706 m_presentevent.notifyAll();
711 void CXBMCRenderManager::Reset()
713 CSharedLock lock(m_sharedSection);
715 m_pRenderer->Reset();
718 RESOLUTION CXBMCRenderManager::GetResolution()
720 CSharedLock lock(m_sharedSection);
722 return m_pRenderer->GetResolution();
727 float CXBMCRenderManager::GetMaximumFPS()
731 if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
733 fps = (float)g_VideoReferenceClock.GetRefreshRate();
734 if (fps <= 0) fps = g_graphicsContext.GetFPS();
742 void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
745 m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
748 void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
751 m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
754 void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
756 CSharedLock lock(m_sharedSection);
758 SPresent& m = m_Queue[m_presentsource];
760 if( m.presentmethod == PRESENT_METHOD_BOB )
761 PresentFields(clear, flags, alpha);
762 else if( m.presentmethod == PRESENT_METHOD_WEAVE )
763 PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
764 else if( m.presentmethod == PRESENT_METHOD_BLEND )
765 PresentBlend(clear, flags, alpha);
767 PresentSingle(clear, flags, alpha);
769 m_overlays.Render(m_presentsource);
772 /* simple present method */
773 void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
775 CSingleLock lock(g_graphicsContext);
777 m_pRenderer->RenderUpdate(clear, flags, alpha);
780 /* new simpler method of handling interlaced material, *
781 * we just render the two fields right after eachother */
782 void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
784 CSingleLock lock(g_graphicsContext);
785 SPresent& m = m_Queue[m_presentsource];
787 if(m_presentstep == PRESENT_FRAME)
789 if( m.presentfield == FS_BOT)
790 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
792 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
796 if( m.presentfield == FS_TOP)
797 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
799 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
803 void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
805 CSingleLock lock(g_graphicsContext);
806 SPresent& m = m_Queue[m_presentsource];
808 if( m.presentfield == FS_BOT )
810 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
811 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
815 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
816 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
820 void CXBMCRenderManager::Recover()
822 #if defined(HAS_GL) && !defined(TARGET_DARWIN)
823 glFlush(); // attempt to have gpu done with pixmap and vdpau
826 UpdateDisplayLatency();
829 void CXBMCRenderManager::UpdateDisplayLatency()
831 float refresh = g_graphicsContext.GetFPS();
832 if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
833 refresh = 0; // No idea about refresh rate when windowed, just get the default latency
834 m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
835 CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
838 void CXBMCRenderManager::UpdateResolution()
842 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
843 if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
845 RESOLUTION res = GetResolution();
846 g_graphicsContext.SetVideoResolution(res);
848 m_bReconfigured = false;
853 unsigned int CXBMCRenderManager::GetProcessorSize()
855 CSharedLock lock(m_sharedSection);
856 return std::max(4, NUM_BUFFERS);
859 // Supported pixel formats, can be called before configure
860 std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
862 CSharedLock lock(m_sharedSection);
864 return m_pRenderer->SupportedFormats();
865 return std::vector<ERenderFormat>();
868 int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
870 CSharedLock lock(m_sharedSection);
876 CSingleLock lock(m_presentlock);
879 index = m_free.front();
882 if(m_pRenderer->AddVideoPicture(&pic, index))
886 if (m_pRenderer->GetImage(&image, index) < 0)
889 if(pic.format == RENDER_FMT_YUV420P
890 || pic.format == RENDER_FMT_YUV420P10
891 || pic.format == RENDER_FMT_YUV420P16)
893 CDVDCodecUtils::CopyPicture(&image, &pic);
895 else if(pic.format == RENDER_FMT_NV12)
897 CDVDCodecUtils::CopyNV12Picture(&image, &pic);
899 else if(pic.format == RENDER_FMT_YUYV422
900 || pic.format == RENDER_FMT_UYVY422)
902 CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
904 else if(pic.format == RENDER_FMT_DXVA)
906 CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
909 else if(pic.format == RENDER_FMT_VDPAU
910 || pic.format == RENDER_FMT_VDPAU_420)
911 m_pRenderer->AddProcessor(pic.vdpau, index);
913 #ifdef HAVE_LIBOPENMAX
914 else if(pic.format == RENDER_FMT_OMXEGL)
915 m_pRenderer->AddProcessor(pic.openMax, &pic, index);
918 else if(pic.format == RENDER_FMT_CVBREF)
919 m_pRenderer->AddProcessor(pic.cvBufferRef, index);
922 else if(pic.format == RENDER_FMT_VAAPI)
923 m_pRenderer->AddProcessor(*pic.vaapi, index);
925 #ifdef HAS_LIBSTAGEFRIGHT
926 else if(pic.format == RENDER_FMT_EGLIMG)
927 m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
929 #if defined(TARGET_ANDROID)
930 else if(pic.format == RENDER_FMT_MEDIACODEC)
931 m_pRenderer->AddProcessor(pic.mediacodec, index);
934 m_pRenderer->ReleaseImage(index, false);
939 bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
941 CSharedLock lock(m_sharedSection);
943 return m_pRenderer->Supports(feature);
948 bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
950 CSharedLock lock(m_sharedSection);
952 return m_pRenderer->Supports(method);
957 bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
959 CSharedLock lock(m_sharedSection);
961 return m_pRenderer->Supports(method);
966 bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
968 CSharedLock lock(m_sharedSection);
970 return m_pRenderer->Supports(method);
975 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
977 CSharedLock lock(m_sharedSection);
978 return AutoInterlaceMethodInternal(mInt);
981 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
983 if (mInt == VS_INTERLACEMETHOD_NONE)
984 return VS_INTERLACEMETHOD_NONE;
986 if(!m_pRenderer->Supports(mInt))
987 mInt = VS_INTERLACEMETHOD_AUTO;
989 if (mInt == VS_INTERLACEMETHOD_AUTO)
990 return m_pRenderer->AutoInterlaceMethod();
995 int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
997 CSingleLock lock2(m_presentlock);
999 XbmcThreads::EndTime endtime(timeout);
1000 while(m_free.empty())
1002 m_presentevent.wait(lock2, std::min(50, timeout));
1003 if(endtime.IsTimePast() || bStop)
1005 if (timeout != 0 && !bStop)
1006 CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
1011 // make sure overlay buffer is released, this won't happen on AddOverlay
1012 m_overlays.Release(m_free.front());
1014 // return buffer level
1015 return m_queued.size() + m_discard.size();;
1018 void CXBMCRenderManager::PrepareNextRender()
1020 CSingleLock lock(m_presentlock);
1022 if (m_queued.empty())
1024 CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
1025 m_presentstep = PRESENT_IDLE;
1026 m_presentevent.notifyAll();
1030 double clocktime = GetPresentTime();
1031 double frametime = 1.0 / GetMaximumFPS();
1033 /* see if any future queued frames are already due */
1034 std::deque<int>::reverse_iterator curr, prev;
1036 curr = prev = m_queued.rbegin();
1038 while (prev != m_queued.rend())
1040 if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
1041 && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
1048 /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
1050 if(g_graphicsContext.IsFullScreenVideo())
1051 next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
1053 next = (m_Queue[idx].timestamp <= clocktime + frametime);
1057 /* skip late frames */
1058 while(m_queued.front() != idx)
1060 requeue(m_discard, m_queued);
1064 m_presentstep = PRESENT_FLIP;
1065 m_discard.push_back(m_presentsource);
1066 m_presentsource = idx;
1067 m_queued.pop_front();
1068 m_presentevent.notifyAll();
1072 void CXBMCRenderManager::DiscardBuffer()
1074 CSharedLock lock(m_sharedSection);
1075 CSingleLock lock2(m_presentlock);
1077 while(!m_queued.empty())
1078 requeue(m_discard, m_queued);
1080 if(m_presentstep == PRESENT_READY)
1081 m_presentstep = PRESENT_IDLE;
1082 m_presentevent.notifyAll();