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"
39 #include "guilib/GUIFontManager.h"
42 #include "LinuxRendererGL.h"
44 #include "LinuxRendererGLES.h"
46 #include "WinRenderer.h"
47 #elif defined(HAS_SDL)
48 #include "LinuxRenderer.h"
51 #include "RenderCapture.h"
53 /* to use the same as player */
54 #include "../dvdplayer/DVDClock.h"
55 #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
56 #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h"
58 #define MAXPRESENTDELAY 0.500
60 /* at any point we want an exclusive lock on rendermanager */
61 /* we must make sure we don't have a graphiccontext lock */
62 /* these two functions allow us to step out from that lock */
63 /* and reaquire it after having the exclusive lock */
69 CRetakeLock(CSharedSection §ion, CCriticalSection &owned = g_graphicsContext)
70 : m_count(owned.exit())
74 m_owned.restore(m_count);
77 void Leave() { m_lock.Leave(); }
80 m_count = m_owned.exit();
82 m_owned.restore(m_count);
88 CCriticalSection &m_owned;
91 static void requeue(std::deque<int> &trg, std::deque<int> &src)
93 trg.push_back(src.front());
97 CXBMCRenderManager::CXBMCRenderManager()
100 m_bIsStarted = false;
102 m_presentstep = PRESENT_IDLE;
105 m_bReconfigured = false;
106 m_hasCaptures = false;
107 m_displayLatency = 0.0f;
110 memset(&m_errorbuff, 0, ERRORBUFFSIZE);
114 m_format = RENDER_FMT_NONE;
117 CXBMCRenderManager::~CXBMCRenderManager()
123 void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
125 CSharedLock lock(m_sharedSection);
127 m_pRenderer->GetVideoRect(source, dest);
130 float CXBMCRenderManager::GetAspectRatio()
132 CSharedLock lock(m_sharedSection);
134 return m_pRenderer->GetAspectRatio();
139 /* These is based on CurrentHostCounter() */
140 double CXBMCRenderManager::GetPresentTime()
142 return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
145 static double wrap(double x, double minimum, double maximum)
150 x = fmod(x - minimum, maximum - minimum) + minimum;
152 x += maximum - minimum;
154 x -= maximum - minimum;
158 void CXBMCRenderManager::WaitPresentTime(double presenttime)
161 int fps = g_VideoReferenceClock.GetRefreshRate(&frametime);
164 /* smooth video not enabled */
165 CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE);
169 double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE;
171 double error = ( clock - presenttime ) / frametime - target;
173 m_presenterr = error;
175 // correct error so it targets the closest vblank
176 error = wrap(error, 0.0 - target, 1.0 - target);
178 // scale the error used for correction,
179 // based on how much buffer we have on
180 // that side of the target
182 error /= 2.0 * (1.0 - target);
184 error /= 2.0 * (0.0 + target);
186 //save error in the buffer
187 m_errorindex = (m_errorindex + 1) % ERRORBUFFSIZE;
188 m_errorbuff[m_errorindex] = error;
190 //get the average error from the buffer
191 double avgerror = 0.0;
192 for (int i = 0; i < ERRORBUFFSIZE; i++)
193 avgerror += m_errorbuff[i];
195 avgerror /= ERRORBUFFSIZE;
198 //we change the clock speed slightly
199 //to make every frame's presenttime end up in the middle of two vblanks
200 //integral correction, clamp to -0.5:0.5 range
201 m_presentcorr = std::max(std::min(m_presentcorr + avgerror * 0.01, 0.1), -0.1);
202 g_VideoReferenceClock.SetFineAdjust(1.0 - avgerror * 0.01 - m_presentcorr * 0.01);
204 //printf("%f %f % 2.0f%% % f % f\n", presenttime, clock, m_presentcorr * 100, error, error_org);
207 CStdString CXBMCRenderManager::GetVSyncState()
209 double avgerror = 0.0;
210 for (int i = 0; i < ERRORBUFFSIZE; i++)
211 avgerror += m_errorbuff[i];
212 avgerror /= ERRORBUFFSIZE;
215 state.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();
262 m_QueueSize = buffers - processor + 1; /* respect maximum refs */
264 m_QueueSize = m_pRenderer->GetMaxBufferSize(); /* no refs to data */
266 m_QueueSize = std::min(m_QueueSize, (int)m_pRenderer->GetMaxBufferSize());
267 m_QueueSize = std::min(m_QueueSize, NUM_BUFFERS);
271 CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, processor, buffers);
274 m_pRenderer->SetBufferSize(m_QueueSize);
275 m_pRenderer->Update();
281 for (int i=1; i < m_QueueSize; i++)
285 m_bReconfigured = true;
286 m_presentstep = PRESENT_IDLE;
287 m_presentevent.notifyAll();
289 m_firstFlipPage = false; // tempfix
291 CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize);
297 bool CXBMCRenderManager::RendererHandlesPresent() const
299 return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
302 bool CXBMCRenderManager::IsConfigured() const
306 return m_pRenderer->IsConfigured();
309 void CXBMCRenderManager::Update()
311 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
314 m_pRenderer->Update();
317 bool CXBMCRenderManager::FrameWait(int ms)
319 XbmcThreads::EndTime timeout(ms);
320 CSingleLock lock(m_presentlock);
321 while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast())
322 m_presentevent.wait(lock, timeout.MillisLeft());
323 return m_presentstep != PRESENT_IDLE;
326 void CXBMCRenderManager::FrameMove()
328 { CSharedLock lock(m_sharedSection);
329 CSingleLock lock2(m_presentlock);
334 if (m_presentstep == PRESENT_FRAME2)
336 if(!m_queued.empty())
338 double timestamp = GetPresentTime();
339 SPresent& m = m_Queue[m_presentsource];
340 SPresent& q = m_Queue[m_queued.front()];
341 if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
343 m_presentstep = PRESENT_READY;
344 m_presentevent.notifyAll();
349 if (m_presentstep == PRESENT_READY)
352 if(m_presentstep == PRESENT_FLIP)
354 m_pRenderer->FlipPage(m_presentsource);
355 m_presentstep = PRESENT_FRAME;
356 m_presentevent.notifyAll();
359 /* release all previous */
360 for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
362 // TODO check for fence
363 m_pRenderer->ReleaseBuffer(*it);
364 m_overlays.Release(*it);
365 m_free.push_back(*it);
366 it = m_discard.erase(it);
371 void CXBMCRenderManager::FrameFinish()
373 /* wait for this present to be valid */
374 SPresent& m = m_Queue[m_presentsource];
376 if(g_graphicsContext.IsFullScreenVideo())
377 WaitPresentTime(m.timestamp);
379 { CSingleLock lock(m_presentlock);
381 if(m_presentstep == PRESENT_FRAME)
383 if( m.presentmethod == PRESENT_METHOD_BOB
384 || m.presentmethod == PRESENT_METHOD_WEAVE)
385 m_presentstep = PRESENT_FRAME2;
387 m_presentstep = PRESENT_IDLE;
389 else if(m_presentstep == PRESENT_FRAME2)
390 m_presentstep = PRESENT_IDLE;
393 if(m_presentstep == PRESENT_IDLE)
395 if(!m_queued.empty())
396 m_presentstep = PRESENT_READY;
399 m_presentevent.notifyAll();
403 unsigned int CXBMCRenderManager::PreInit()
405 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
410 memset(m_errorbuff, 0, sizeof(m_errorbuff));
412 m_bIsStarted = false;
416 m_pRenderer = new CLinuxRendererGL();
418 m_pRenderer = new CLinuxRendererGLES();
419 #elif defined(HAS_DX)
420 m_pRenderer = new CWinRenderer();
421 #elif defined(HAS_SDL)
422 m_pRenderer = new CLinuxRenderer();
426 UpdateDisplayLatency();
431 return m_pRenderer->PreInit();
434 void CXBMCRenderManager::UnInit()
436 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
438 m_bIsStarted = false;
441 g_fontManager.Unload("__subtitle__");
442 g_fontManager.Unload("__subtitleborder__");
444 // free renderer resources.
445 // TODO: we may also want to release the renderer here.
447 m_pRenderer->UnInit();
450 bool CXBMCRenderManager::Flush()
455 if (g_application.IsCurrentThread())
457 CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
459 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
460 m_pRenderer->Flush();
466 ThreadMessage msg = {TMSG_RENDERER_FLUSH};
467 m_flushEvent.Reset();
468 CApplicationMessenger::Get().SendMessage(msg, false);
469 if (!m_flushEvent.WaitMSec(1000))
471 CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
480 void CXBMCRenderManager::SetupScreenshot()
482 CSharedLock lock(m_sharedSection);
484 m_pRenderer->SetupScreenshot();
487 CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
489 return new CRenderCapture;
492 void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
494 CSingleLock lock(m_captCritSect);
496 RemoveCapture(capture);
498 //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
499 if (g_application.IsCurrentThread())
505 capture->SetState(CAPTURESTATE_NEEDSDELETE);
506 m_captures.push_back(capture);
509 if (!m_captures.empty())
510 m_hasCaptures = true;
513 void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
515 CSingleLock lock(m_captCritSect);
517 RemoveCapture(capture);
519 capture->SetState(CAPTURESTATE_NEEDSRENDER);
520 capture->SetUserState(CAPTURESTATE_WORKING);
521 capture->SetWidth(width);
522 capture->SetHeight(height);
523 capture->SetFlags(flags);
524 capture->GetEvent().Reset();
526 if (g_application.IsCurrentThread())
528 if (flags & CAPTUREFLAG_IMMEDIATELY)
530 //render capture and read out immediately
531 RenderCapture(capture);
532 capture->SetUserState(capture->GetState());
533 capture->GetEvent().Set();
536 if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
538 //schedule this capture for a render and readout
539 m_captures.push_back(capture);
544 //schedule this capture for a render and readout
545 m_captures.push_back(capture);
548 if (!m_captures.empty())
549 m_hasCaptures = true;
552 void CXBMCRenderManager::ManageCaptures()
554 //no captures, return here so we don't do an unnecessary lock
558 CSingleLock lock(m_captCritSect);
560 std::list<CRenderCapture*>::iterator it = m_captures.begin();
561 while (it != m_captures.end())
563 CRenderCapture* capture = *it;
565 if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
568 it = m_captures.erase(it);
572 if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
573 RenderCapture(capture);
574 else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
577 if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
579 //tell the thread that the capture is done or has failed
580 capture->SetUserState(capture->GetState());
581 capture->GetEvent().Set();
583 if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
585 capture->SetState(CAPTURESTATE_NEEDSRENDER);
587 //if rendering this capture continuously, and readout is async, render a new capture immediately
588 if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
589 RenderCapture(capture);
595 it = m_captures.erase(it);
604 if (m_captures.empty())
605 m_hasCaptures = false;
608 void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
610 CSharedLock lock(m_sharedSection);
611 if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
612 capture->SetState(CAPTURESTATE_FAILED);
615 void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
617 //remove this CRenderCapture from the list
618 std::list<CRenderCapture*>::iterator it;
619 while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
620 m_captures.erase(it);
623 void CXBMCRenderManager::SetViewMode(int iViewMode)
625 CSharedLock lock(m_sharedSection);
627 m_pRenderer->SetViewMode(iViewMode);
630 void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
632 { CSharedLock lock(m_sharedSection);
637 if(!m_pRenderer) return;
639 m_firstFlipPage = true; // tempfix
641 EPRESENTMETHOD presentmethod;
643 EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
644 EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
646 if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
647 deinterlacemode = VS_DEINTERLACEMODE_OFF;
649 if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
650 presentmethod = PRESENT_METHOD_SINGLE;
653 if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
654 presentmethod = PRESENT_METHOD_SINGLE;
658 if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
659 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
660 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
661 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
662 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
663 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
664 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
665 else presentmethod = PRESENT_METHOD_SINGLE;
667 /* default to odd field if we want to deinterlace and don't know better */
668 if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
671 /* invert present field */
682 /* failsafe for invalid timestamps, to make sure queue always empties */
683 if(timestamp > GetPresentTime() + 5.0)
684 timestamp = GetPresentTime() + 5.0;
686 CSingleLock lock2(m_presentlock);
692 source = m_free.front();
694 SPresent& m = m_Queue[source];
695 m.timestamp = timestamp;
696 m.presentfield = sync;
697 m.presentmethod = presentmethod;
698 requeue(m_queued, m_free);
700 /* signal to any waiters to check state */
701 if(m_presentstep == PRESENT_IDLE)
703 m_presentstep = PRESENT_READY;
704 m_presentevent.notifyAll();
709 void CXBMCRenderManager::Reset()
711 CSharedLock lock(m_sharedSection);
713 m_pRenderer->Reset();
716 RESOLUTION CXBMCRenderManager::GetResolution()
718 CSharedLock lock(m_sharedSection);
720 return m_pRenderer->GetResolution();
725 float CXBMCRenderManager::GetMaximumFPS()
729 if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
731 fps = (float)g_VideoReferenceClock.GetRefreshRate();
732 if (fps <= 0) fps = g_graphicsContext.GetFPS();
740 void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
743 m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
746 void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
749 m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
752 void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
754 CSharedLock lock(m_sharedSection);
756 SPresent& m = m_Queue[m_presentsource];
758 if( m.presentmethod == PRESENT_METHOD_BOB )
759 PresentFields(clear, flags, alpha);
760 else if( m.presentmethod == PRESENT_METHOD_WEAVE )
761 PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
762 else if( m.presentmethod == PRESENT_METHOD_BLEND )
763 PresentBlend(clear, flags, alpha);
765 PresentSingle(clear, flags, alpha);
767 m_overlays.Render(m_presentsource);
770 /* simple present method */
771 void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
773 CSingleLock lock(g_graphicsContext);
775 m_pRenderer->RenderUpdate(clear, flags, alpha);
778 /* new simpler method of handling interlaced material, *
779 * we just render the two fields right after eachother */
780 void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
782 CSingleLock lock(g_graphicsContext);
783 SPresent& m = m_Queue[m_presentsource];
785 if(m_presentstep == PRESENT_FRAME)
787 if( m.presentfield == FS_BOT)
788 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
790 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
794 if( m.presentfield == FS_TOP)
795 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
797 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
801 void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
803 CSingleLock lock(g_graphicsContext);
804 SPresent& m = m_Queue[m_presentsource];
806 if( m.presentfield == FS_BOT )
808 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
809 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
813 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
814 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
818 void CXBMCRenderManager::Recover()
820 #if defined(HAS_GL) && !defined(TARGET_DARWIN)
821 glFlush(); // attempt to have gpu done with pixmap and vdpau
824 UpdateDisplayLatency();
827 void CXBMCRenderManager::UpdateDisplayLatency()
829 float refresh = g_graphicsContext.GetFPS();
830 if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
831 refresh = 0; // No idea about refresh rate when windowed, just get the default latency
832 m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
833 CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
836 void CXBMCRenderManager::UpdateResolution()
840 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
841 if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
843 RESOLUTION res = GetResolution();
844 g_graphicsContext.SetVideoResolution(res);
846 m_bReconfigured = false;
851 unsigned int CXBMCRenderManager::GetProcessorSize()
853 CSharedLock lock(m_sharedSection);
854 return std::max(4, NUM_BUFFERS);
857 // Supported pixel formats, can be called before configure
858 std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
860 CSharedLock lock(m_sharedSection);
862 return m_pRenderer->SupportedFormats();
863 return std::vector<ERenderFormat>();
866 int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
868 CSharedLock lock(m_sharedSection);
874 CSingleLock lock(m_presentlock);
877 index = m_free.front();
880 if(m_pRenderer->AddVideoPicture(&pic, index))
884 if (m_pRenderer->GetImage(&image, index) < 0)
887 if(pic.format == RENDER_FMT_YUV420P
888 || pic.format == RENDER_FMT_YUV420P10
889 || pic.format == RENDER_FMT_YUV420P16)
891 CDVDCodecUtils::CopyPicture(&image, &pic);
893 else if(pic.format == RENDER_FMT_NV12)
895 CDVDCodecUtils::CopyNV12Picture(&image, &pic);
897 else if(pic.format == RENDER_FMT_YUYV422
898 || pic.format == RENDER_FMT_UYVY422)
900 CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
902 else if(pic.format == RENDER_FMT_DXVA)
904 CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
907 else if(pic.format == RENDER_FMT_VDPAU
908 || pic.format == RENDER_FMT_VDPAU_420)
909 m_pRenderer->AddProcessor(pic.vdpau, index);
911 #ifdef HAVE_LIBOPENMAX
912 else if(pic.format == RENDER_FMT_OMXEGL)
913 m_pRenderer->AddProcessor(pic.openMax, &pic, index);
916 else if(pic.format == RENDER_FMT_CVBREF)
917 m_pRenderer->AddProcessor(pic.cvBufferRef, index);
920 else if(pic.format == RENDER_FMT_VAAPI)
921 m_pRenderer->AddProcessor(*pic.vaapi, index);
923 #ifdef HAS_LIBSTAGEFRIGHT
924 else if(pic.format == RENDER_FMT_EGLIMG)
925 m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
927 #if defined(TARGET_ANDROID)
928 else if(pic.format == RENDER_FMT_MEDIACODEC)
929 m_pRenderer->AddProcessor(pic.mediacodec, index);
932 m_pRenderer->ReleaseImage(index, false);
937 bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
939 CSharedLock lock(m_sharedSection);
941 return m_pRenderer->Supports(feature);
946 bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
948 CSharedLock lock(m_sharedSection);
950 return m_pRenderer->Supports(method);
955 bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
957 CSharedLock lock(m_sharedSection);
959 return m_pRenderer->Supports(method);
964 bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
966 CSharedLock lock(m_sharedSection);
968 return m_pRenderer->Supports(method);
973 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
975 CSharedLock lock(m_sharedSection);
976 return AutoInterlaceMethodInternal(mInt);
979 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
981 if (mInt == VS_INTERLACEMETHOD_NONE)
982 return VS_INTERLACEMETHOD_NONE;
984 if(!m_pRenderer->Supports(mInt))
985 mInt = VS_INTERLACEMETHOD_AUTO;
987 if (mInt == VS_INTERLACEMETHOD_AUTO)
988 return m_pRenderer->AutoInterlaceMethod();
993 int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
995 CSingleLock lock2(m_presentlock);
997 XbmcThreads::EndTime endtime(timeout);
998 while(m_free.empty())
1000 m_presentevent.wait(lock2, std::min(50, timeout));
1001 if(endtime.IsTimePast() || bStop)
1003 if (timeout != 0 && !bStop)
1004 CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
1009 // make sure overlay buffer is released, this won't happen on AddOverlay
1010 m_overlays.Release(m_free.front());
1012 // return buffer level
1013 return m_queued.size() + m_discard.size();;
1016 void CXBMCRenderManager::PrepareNextRender()
1018 CSingleLock lock(m_presentlock);
1020 if (m_queued.empty())
1022 CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
1023 m_presentstep = PRESENT_IDLE;
1024 m_presentevent.notifyAll();
1028 double clocktime = GetPresentTime();
1029 double frametime = 1.0 / GetMaximumFPS();
1031 /* see if any future queued frames are already due */
1032 std::deque<int>::reverse_iterator curr, prev;
1034 curr = prev = m_queued.rbegin();
1036 while (prev != m_queued.rend())
1038 if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
1039 && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
1046 /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
1048 if(g_graphicsContext.IsFullScreenVideo())
1049 next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
1051 next = (m_Queue[idx].timestamp <= clocktime + frametime);
1055 /* skip late frames */
1056 while(m_queued.front() != idx)
1058 requeue(m_discard, m_queued);
1062 m_presentstep = PRESENT_FLIP;
1063 m_discard.push_back(m_presentsource);
1064 m_presentsource = idx;
1065 m_queued.pop_front();
1066 m_presentevent.notifyAll();
1070 void CXBMCRenderManager::DiscardBuffer()
1072 CSharedLock lock(m_sharedSection);
1073 CSingleLock lock2(m_presentlock);
1075 while(!m_queued.empty())
1076 requeue(m_discard, m_queued);
1078 if(m_presentstep == PRESENT_READY)
1079 m_presentstep = PRESENT_IDLE;
1080 m_presentevent.notifyAll();