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 m_clock_framefinish = GetPresentTime();
383 { CSingleLock lock(m_presentlock);
385 if(m_presentstep == PRESENT_FRAME)
387 if( m.presentmethod == PRESENT_METHOD_BOB
388 || m.presentmethod == PRESENT_METHOD_WEAVE)
389 m_presentstep = PRESENT_FRAME2;
391 m_presentstep = PRESENT_IDLE;
393 else if(m_presentstep == PRESENT_FRAME2)
394 m_presentstep = PRESENT_IDLE;
397 if(m_presentstep == PRESENT_IDLE)
399 if(!m_queued.empty())
400 m_presentstep = PRESENT_READY;
403 m_presentevent.notifyAll();
407 unsigned int CXBMCRenderManager::PreInit()
409 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
414 memset(m_errorbuff, 0, sizeof(m_errorbuff));
416 m_bIsStarted = false;
420 m_pRenderer = new CLinuxRendererGL();
422 m_pRenderer = new CLinuxRendererGLES();
423 #elif defined(HAS_DX)
424 m_pRenderer = new CWinRenderer();
425 #elif defined(HAS_SDL)
426 m_pRenderer = new CLinuxRenderer();
430 UpdateDisplayLatency();
435 return m_pRenderer->PreInit();
438 void CXBMCRenderManager::UnInit()
440 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
442 m_bIsStarted = false;
445 g_fontManager.Unload("__subtitle__");
446 g_fontManager.Unload("__subtitleborder__");
448 // free renderer resources.
449 // TODO: we may also want to release the renderer here.
451 m_pRenderer->UnInit();
454 bool CXBMCRenderManager::Flush()
459 if (g_application.IsCurrentThread())
461 CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
463 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
464 m_pRenderer->Flush();
470 ThreadMessage msg = {TMSG_RENDERER_FLUSH};
471 m_flushEvent.Reset();
472 CApplicationMessenger::Get().SendMessage(msg, false);
473 if (!m_flushEvent.WaitMSec(1000))
475 CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
484 void CXBMCRenderManager::SetupScreenshot()
486 CSharedLock lock(m_sharedSection);
488 m_pRenderer->SetupScreenshot();
491 CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
493 return new CRenderCapture;
496 void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
498 CSingleLock lock(m_captCritSect);
500 RemoveCapture(capture);
502 //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
503 if (g_application.IsCurrentThread())
509 capture->SetState(CAPTURESTATE_NEEDSDELETE);
510 m_captures.push_back(capture);
513 if (!m_captures.empty())
514 m_hasCaptures = true;
517 void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
519 CSingleLock lock(m_captCritSect);
521 RemoveCapture(capture);
523 capture->SetState(CAPTURESTATE_NEEDSRENDER);
524 capture->SetUserState(CAPTURESTATE_WORKING);
525 capture->SetWidth(width);
526 capture->SetHeight(height);
527 capture->SetFlags(flags);
528 capture->GetEvent().Reset();
530 if (g_application.IsCurrentThread())
532 if (flags & CAPTUREFLAG_IMMEDIATELY)
534 //render capture and read out immediately
535 RenderCapture(capture);
536 capture->SetUserState(capture->GetState());
537 capture->GetEvent().Set();
540 if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
542 //schedule this capture for a render and readout
543 m_captures.push_back(capture);
548 //schedule this capture for a render and readout
549 m_captures.push_back(capture);
552 if (!m_captures.empty())
553 m_hasCaptures = true;
556 void CXBMCRenderManager::ManageCaptures()
558 //no captures, return here so we don't do an unnecessary lock
562 CSingleLock lock(m_captCritSect);
564 std::list<CRenderCapture*>::iterator it = m_captures.begin();
565 while (it != m_captures.end())
567 CRenderCapture* capture = *it;
569 if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
572 it = m_captures.erase(it);
576 if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
577 RenderCapture(capture);
578 else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
581 if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
583 //tell the thread that the capture is done or has failed
584 capture->SetUserState(capture->GetState());
585 capture->GetEvent().Set();
587 if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
589 capture->SetState(CAPTURESTATE_NEEDSRENDER);
591 //if rendering this capture continuously, and readout is async, render a new capture immediately
592 if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
593 RenderCapture(capture);
599 it = m_captures.erase(it);
608 if (m_captures.empty())
609 m_hasCaptures = false;
612 void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
614 CSharedLock lock(m_sharedSection);
615 if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
616 capture->SetState(CAPTURESTATE_FAILED);
619 void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
621 //remove this CRenderCapture from the list
622 std::list<CRenderCapture*>::iterator it;
623 while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
624 m_captures.erase(it);
627 void CXBMCRenderManager::SetViewMode(int iViewMode)
629 CSharedLock lock(m_sharedSection);
631 m_pRenderer->SetViewMode(iViewMode);
634 void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
636 { CSharedLock lock(m_sharedSection);
641 if(!m_pRenderer) return;
643 m_firstFlipPage = true; // tempfix
645 EPRESENTMETHOD presentmethod;
647 EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
648 EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
650 if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
651 deinterlacemode = VS_DEINTERLACEMODE_OFF;
653 if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
654 presentmethod = PRESENT_METHOD_SINGLE;
657 if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
658 presentmethod = PRESENT_METHOD_SINGLE;
662 if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
663 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
664 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
665 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
666 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
667 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
668 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
669 else presentmethod = PRESENT_METHOD_SINGLE;
671 /* default to odd field if we want to deinterlace and don't know better */
672 if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
675 /* invert present field */
686 /* failsafe for invalid timestamps, to make sure queue always empties */
687 if(timestamp > GetPresentTime() + 5.0)
688 timestamp = GetPresentTime() + 5.0;
690 CSingleLock lock2(m_presentlock);
696 source = m_free.front();
698 SPresent& m = m_Queue[source];
699 m.timestamp = timestamp;
700 m.presentfield = sync;
701 m.presentmethod = presentmethod;
702 requeue(m_queued, m_free);
704 /* signal to any waiters to check state */
705 if(m_presentstep == PRESENT_IDLE)
707 m_presentstep = PRESENT_READY;
708 m_presentevent.notifyAll();
713 void CXBMCRenderManager::Reset()
715 CSharedLock lock(m_sharedSection);
717 m_pRenderer->Reset();
720 RESOLUTION CXBMCRenderManager::GetResolution()
722 CSharedLock lock(m_sharedSection);
724 return m_pRenderer->GetResolution();
729 float CXBMCRenderManager::GetMaximumFPS()
733 if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
735 fps = (float)g_VideoReferenceClock.GetRefreshRate();
736 if (fps <= 0) fps = g_graphicsContext.GetFPS();
744 void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
747 m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
750 void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
753 m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
756 void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
758 CSharedLock lock(m_sharedSection);
760 SPresent& m = m_Queue[m_presentsource];
762 if( m.presentmethod == PRESENT_METHOD_BOB )
763 PresentFields(clear, flags, alpha);
764 else if( m.presentmethod == PRESENT_METHOD_WEAVE )
765 PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
766 else if( m.presentmethod == PRESENT_METHOD_BLEND )
767 PresentBlend(clear, flags, alpha);
769 PresentSingle(clear, flags, alpha);
771 m_overlays.Render(m_presentsource);
774 /* simple present method */
775 void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
777 CSingleLock lock(g_graphicsContext);
779 m_pRenderer->RenderUpdate(clear, flags, alpha);
782 /* new simpler method of handling interlaced material, *
783 * we just render the two fields right after eachother */
784 void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
786 CSingleLock lock(g_graphicsContext);
787 SPresent& m = m_Queue[m_presentsource];
789 if(m_presentstep == PRESENT_FRAME)
791 if( m.presentfield == FS_BOT)
792 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
794 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
798 if( m.presentfield == FS_TOP)
799 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
801 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
805 void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
807 CSingleLock lock(g_graphicsContext);
808 SPresent& m = m_Queue[m_presentsource];
810 if( m.presentfield == FS_BOT )
812 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
813 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
817 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
818 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
822 void CXBMCRenderManager::Recover()
824 #if defined(HAS_GL) && !defined(TARGET_DARWIN)
825 glFlush(); // attempt to have gpu done with pixmap and vdpau
828 UpdateDisplayLatency();
831 void CXBMCRenderManager::UpdateDisplayLatency()
833 float refresh = g_graphicsContext.GetFPS();
834 if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
835 refresh = 0; // No idea about refresh rate when windowed, just get the default latency
836 m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
837 CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
840 void CXBMCRenderManager::UpdateResolution()
844 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
845 if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
847 RESOLUTION res = GetResolution();
848 g_graphicsContext.SetVideoResolution(res);
850 m_bReconfigured = false;
855 unsigned int CXBMCRenderManager::GetProcessorSize()
857 CSharedLock lock(m_sharedSection);
858 return std::max(4, NUM_BUFFERS);
861 // Supported pixel formats, can be called before configure
862 std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
864 CSharedLock lock(m_sharedSection);
866 return m_pRenderer->SupportedFormats();
867 return std::vector<ERenderFormat>();
870 int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
872 CSharedLock lock(m_sharedSection);
878 CSingleLock lock(m_presentlock);
881 index = m_free.front();
884 if(m_pRenderer->AddVideoPicture(&pic, index))
888 if (m_pRenderer->GetImage(&image, index) < 0)
891 if(pic.format == RENDER_FMT_YUV420P
892 || pic.format == RENDER_FMT_YUV420P10
893 || pic.format == RENDER_FMT_YUV420P16)
895 CDVDCodecUtils::CopyPicture(&image, &pic);
897 else if(pic.format == RENDER_FMT_NV12)
899 CDVDCodecUtils::CopyNV12Picture(&image, &pic);
901 else if(pic.format == RENDER_FMT_YUYV422
902 || pic.format == RENDER_FMT_UYVY422)
904 CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
906 else if(pic.format == RENDER_FMT_DXVA)
908 CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
911 else if(pic.format == RENDER_FMT_VDPAU
912 || pic.format == RENDER_FMT_VDPAU_420)
913 m_pRenderer->AddProcessor(pic.vdpau, index);
915 #ifdef HAVE_LIBOPENMAX
916 else if(pic.format == RENDER_FMT_OMXEGL)
917 m_pRenderer->AddProcessor(pic.openMax, &pic, index);
920 else if(pic.format == RENDER_FMT_CVBREF)
921 m_pRenderer->AddProcessor(pic.cvBufferRef, index);
924 else if(pic.format == RENDER_FMT_VAAPI)
925 m_pRenderer->AddProcessor(*pic.vaapi, index);
927 #ifdef HAS_LIBSTAGEFRIGHT
928 else if(pic.format == RENDER_FMT_EGLIMG)
929 m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
931 #if defined(TARGET_ANDROID)
932 else if(pic.format == RENDER_FMT_MEDIACODEC)
933 m_pRenderer->AddProcessor(pic.mediacodec, index);
936 m_pRenderer->ReleaseImage(index, false);
941 bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
943 CSharedLock lock(m_sharedSection);
945 return m_pRenderer->Supports(feature);
950 bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
952 CSharedLock lock(m_sharedSection);
954 return m_pRenderer->Supports(method);
959 bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
961 CSharedLock lock(m_sharedSection);
963 return m_pRenderer->Supports(method);
968 bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
970 CSharedLock lock(m_sharedSection);
972 return m_pRenderer->Supports(method);
977 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
979 CSharedLock lock(m_sharedSection);
980 return AutoInterlaceMethodInternal(mInt);
983 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
985 if (mInt == VS_INTERLACEMETHOD_NONE)
986 return VS_INTERLACEMETHOD_NONE;
988 if(!m_pRenderer->Supports(mInt))
989 mInt = VS_INTERLACEMETHOD_AUTO;
991 if (mInt == VS_INTERLACEMETHOD_AUTO)
992 return m_pRenderer->AutoInterlaceMethod();
997 int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
999 CSingleLock lock2(m_presentlock);
1001 XbmcThreads::EndTime endtime(timeout);
1002 while(m_free.empty())
1004 m_presentevent.wait(lock2, std::min(50, timeout));
1005 if(endtime.IsTimePast() || bStop)
1007 if (timeout != 0 && !bStop)
1008 CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
1013 // make sure overlay buffer is released, this won't happen on AddOverlay
1014 m_overlays.Release(m_free.front());
1016 // return buffer level
1017 return m_queued.size() + m_discard.size();;
1020 void CXBMCRenderManager::PrepareNextRender()
1022 CSingleLock lock(m_presentlock);
1024 if (m_queued.empty())
1026 CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
1027 m_presentstep = PRESENT_IDLE;
1028 m_presentevent.notifyAll();
1032 double clocktime = GetPresentTime();
1033 double frametime = 1.0 / GetMaximumFPS();
1034 double correction = 0.0;
1035 int fps = g_VideoReferenceClock.GetRefreshRate();
1036 if((fps > 0) && g_graphicsContext.IsFullScreenVideo() && (clocktime != m_clock_framefinish))
1038 correction = frametime;
1041 /* see if any future queued frames are already due */
1042 std::deque<int>::reverse_iterator curr, prev;
1044 curr = prev = m_queued.rbegin();
1046 while (prev != m_queued.rend())
1048 if(clocktime > m_Queue[*prev].timestamp + correction /* previous frame is late */
1049 && clocktime > m_Queue[*curr].timestamp - frametime + correction) /* selected frame is close to it's display time */
1056 /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
1058 if(g_graphicsContext.IsFullScreenVideo())
1059 next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
1061 next = (m_Queue[idx].timestamp <= clocktime + frametime);
1065 /* skip late frames */
1066 while(m_queued.front() != idx)
1068 requeue(m_discard, m_queued);
1072 m_presentstep = PRESENT_FLIP;
1073 m_discard.push_back(m_presentsource);
1074 m_presentsource = idx;
1075 m_queued.pop_front();
1076 m_presentevent.notifyAll();
1080 void CXBMCRenderManager::DiscardBuffer()
1082 CSharedLock lock(m_sharedSection);
1083 CSingleLock lock2(m_presentlock);
1085 while(!m_queued.empty())
1086 requeue(m_discard, m_queued);
1088 if(m_presentstep == PRESENT_READY)
1089 m_presentstep = PRESENT_IDLE;
1090 m_presentevent.notifyAll();