void CXBMCRenderManager::FrameMove() { { CSharedLock lock(m_sharedSection); CSingleLock lock2(m_presentlock); if (!m_pRenderer) return; if (m_presentstep == PRESENT_FRAME2) { if(!m_queued.empty()) { double timestamp = GetPresentTime(); SPresent& m = m_Queue[m_presentsource]; SPresent& q = m_Queue[m_queued.front()]; if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5) { m_presentstep = PRESENT_READY; m_presentevent.notifyAll(); } } } if (m_presentstep == PRESENT_READY) PrepareNextRender(); if(m_presentstep == PRESENT_FLIP) { m_pRenderer->FlipPage(m_presentsource); m_presentstep = PRESENT_FRAME; m_presentevent.notifyAll(); } /* release all previous */ for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); ) { // renderer may want to keep the frame for postprocessing if (!m_pRenderer->NeedBufferForRef(*it) || !m_bRenderGUI) { m_pRenderer->ReleaseBuffer(*it); m_overlays.Release(*it); m_free.push_back(*it); it = m_discard.erase(it); } else ++it; } m_bRenderGUI = true; } }
void CXBMCRenderManager::DiscardBuffer() { CSharedLock lock(m_sharedSection); CSingleLock lock2(m_presentlock); while(!m_queued.empty()) requeue(m_discard, m_queued); m_Queue[m_presentsource].timestamp = GetPresentTime(); if(m_presentstep == PRESENT_READY) m_presentstep = PRESENT_IDLE; m_presentevent.notifyAll(); }
bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, unsigned int format) { /* make sure any queued frame was fully presented */ double timeout = m_presenttime + 0.1; while(m_presentstep != PRESENT_IDLE) { if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout) { CLog::Log(LOGWARNING, "CRenderManager::Configure - timeout waiting for previous frame"); break; } }; CRetakeLock<CExclusiveLock> lock(m_sharedSection, false); if(!m_pRenderer) { CLog::Log(LOGERROR, "%s called without a valid Renderer object", __FUNCTION__); return false; } bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format); if(result) { if( flags & CONF_FLAGS_FULLSCREEN ) { lock.Leave(); g_application.getApplicationMessenger().SwitchToFullscreen(); lock.Enter(); } m_pRenderer->Update(false); m_bIsStarted = true; m_bReconfigured = true; m_presentstep = PRESENT_IDLE; m_presentevent.Set(); } return result; }
void CXBMCRenderManager::FrameFinish() { /* wait for this present to be valid */ SPresent& m = m_Queue[m_presentsource]; if(g_graphicsContext.IsFullScreenVideo()) { CSingleExit lock(g_graphicsContext); WaitPresentTime(m.timestamp); } m_clock_framefinish = GetPresentTime(); { CSingleLock lock(m_presentlock); if(m_presentstep == PRESENT_FRAME) { if( m.presentmethod == PRESENT_METHOD_BOB || m.presentmethod == PRESENT_METHOD_WEAVE) m_presentstep = PRESENT_FRAME2; else m_presentstep = PRESENT_IDLE; } else if(m_presentstep == PRESENT_FRAME2) m_presentstep = PRESENT_IDLE; if(m_presentstep == PRESENT_IDLE) { if(!m_queued.empty()) m_presentstep = PRESENT_READY; } m_presentevent.notifyAll(); } }
void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) { if(timestamp - GetPresentTime() > MAXPRESENTDELAY) timestamp = GetPresentTime() + MAXPRESENTDELAY; /* can't flip, untill timestamp */ if(!g_graphicsContext.IsFullScreenVideo()) WaitPresentTime(timestamp); /* make sure any queued frame was fully presented */ double timeout = m_presenttime + 1.0; while(m_presentstep != PRESENT_IDLE && !bStop) { if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) { CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame"); return; } }; if(bStop) return; { CRetakeLock<CExclusiveLock> lock(m_sharedSection); if(!m_pRenderer) return; m_presenttime = timestamp; m_presentfield = sync; m_presentstep = PRESENT_FLIP; m_presentsource = source; EDEINTERLACEMODE deinterlacemode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(g_settings.m_currentVideoSettings.m_InterlaceMethod); bool invert = false; if (deinterlacemode == VS_DEINTERLACEMODE_OFF) m_presentmethod = PRESENT_METHOD_SINGLE; else { if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && m_presentfield == FS_NONE) m_presentmethod = PRESENT_METHOD_SINGLE; else { if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) m_presentmethod = PRESENT_METHOD_BLEND; else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) m_presentmethod = PRESENT_METHOD_WEAVE; else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { m_presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) m_presentmethod = PRESENT_METHOD_BOB; else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { m_presentmethod = PRESENT_METHOD_BOB; invert = true; } else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) m_presentmethod = PRESENT_METHOD_BOB; else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) m_presentmethod = PRESENT_METHOD_BOB; else m_presentmethod = PRESENT_METHOD_SINGLE; /* default to odd field if we want to deinterlace and don't know better */ if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && m_presentfield == FS_NONE) m_presentfield = FS_TOP; /* invert present field */ if(invert) { if( m_presentfield == FS_BOT ) m_presentfield = FS_TOP; else m_presentfield = FS_BOT; } } } } g_application.NewFrame(); /* wait untill render thread have flipped buffers */ timeout = m_presenttime + 1.0; while(m_presentstep == PRESENT_FLIP && !bStop) { if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) { CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete"); return; } } }
void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) { if(timestamp - GetPresentTime() > MAXPRESENTDELAY) timestamp = GetPresentTime() + MAXPRESENTDELAY; /* can't flip, untill timestamp */ if(!g_graphicsContext.IsFullScreenVideo()) WaitPresentTime(timestamp); /* make sure any queued frame was fully presented */ double timeout = m_presenttime + 1.0; while(m_presentstep != PRESENT_IDLE && !bStop) { if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) { CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame"); return; } }; if(bStop) return; { CRetakeLock<CExclusiveLock> lock(m_sharedSection); if(!m_pRenderer) return; m_presenttime = timestamp; m_presentfield = sync; m_presentstep = PRESENT_FLIP; m_presentsource = source; m_presentmethod = g_settings.m_currentVideoSettings.m_InterlaceMethod; /* select render method for auto */ if(m_presentmethod == VS_INTERLACEMETHOD_AUTO) { if(m_presentfield == FS_NONE) m_presentmethod = VS_INTERLACEMETHOD_NONE; else if(m_pRenderer->Supports(VS_INTERLACEMETHOD_RENDER_BOB)) m_presentmethod = VS_INTERLACEMETHOD_RENDER_BOB; else m_presentmethod = VS_INTERLACEMETHOD_NONE; } /* default to odd field if we want to deinterlace and don't know better */ if(m_presentfield == FS_NONE && m_presentmethod != VS_INTERLACEMETHOD_NONE) m_presentfield = FS_TOP; /* invert present field if we have one of those methods */ if( m_presentmethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED || m_presentmethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED ) { if( m_presentfield == FS_BOT ) m_presentfield = FS_TOP; else m_presentfield = FS_BOT; } } g_application.NewFrame(); /* wait untill render thread have flipped buffers */ timeout = m_presenttime + 1.0; while(m_presentstep == PRESENT_FLIP && !bStop) { if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) { CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete"); return; } } }
void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, double pts /* = 0 */, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) { { CSharedLock lock(m_sharedSection); if(bStop) return; if(!m_pRenderer) return; m_firstFlipPage = true; // tempfix EPRESENTMETHOD presentmethod; EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo()) deinterlacemode = VS_DEINTERLACEMODE_OFF; if (deinterlacemode == VS_DEINTERLACEMODE_OFF) presentmethod = PRESENT_METHOD_SINGLE; else { if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE) presentmethod = PRESENT_METHOD_SINGLE; else { bool invert = false; if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND; else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE; else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB; else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; } else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB; else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB; else presentmethod = PRESENT_METHOD_SINGLE; /* default to odd field if we want to deinterlace and don't know better */ if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE) sync = FS_TOP; /* invert present field */ if(invert) { if( sync == FS_BOT ) sync = FS_TOP; else sync = FS_BOT; } } } /* failsafe for invalid timestamps, to make sure queue always empties */ if(timestamp > GetPresentTime() + 5.0) timestamp = GetPresentTime() + 5.0; CSingleLock lock2(m_presentlock); if(m_free.empty()) return; if(source < 0) source = m_free.front(); SPresent& m = m_Queue[source]; m.timestamp = timestamp; m.presentfield = sync; m.presentmethod = presentmethod; m.pts = pts; requeue(m_queued, m_free); /* signal to any waiters to check state */ if(m_presentstep == PRESENT_IDLE) { m_presentstep = PRESENT_READY; m_presentevent.notifyAll(); } } }
void CXBMCRenderManager::PrepareNextRender() { CSingleLock lock(m_presentlock); if (m_queued.empty()) { CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available"); m_presentstep = PRESENT_IDLE; m_presentevent.notifyAll(); return; } double clocktime = GetPresentTime(); double frametime = 1.0 / GetMaximumFPS(); double correction = 0.0; int fps = g_VideoReferenceClock.GetRefreshRate(); if((fps > 0) && g_graphicsContext.IsFullScreenVideo() && (clocktime != m_clock_framefinish)) { correction = frametime; } /* see if any future queued frames are already due */ std::deque<int>::reverse_iterator curr, prev; int idx; curr = prev = m_queued.rbegin(); ++prev; while (prev != m_queued.rend()) { if(clocktime > m_Queue[*prev].timestamp + correction /* previous frame is late */ && clocktime > m_Queue[*curr].timestamp - frametime + correction) /* selected frame is close to it's display time */ break; ++curr; ++prev; } idx = *curr; /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */ bool next; if(g_graphicsContext.IsFullScreenVideo()) next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY); else next = (m_Queue[idx].timestamp <= clocktime + frametime); if (next) { /* skip late frames */ while(m_queued.front() != idx) { requeue(m_discard, m_queued); m_QueueSkip++; } m_presentstep = PRESENT_FLIP; m_discard.push_back(m_presentsource); m_presentsource = idx; m_queued.pop_front(); m_sleeptime = m_Queue[idx].timestamp - clocktime; m_presentpts = m_Queue[idx].pts; m_presentevent.notifyAll(); } }