diff options
author | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2016-04-13 09:20:01 +0200 |
---|---|---|
committer | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2016-04-29 15:57:13 +0200 |
commit | b4dbbb1aefcb78377e78fb9eb14c2c905d634859 (patch) | |
tree | 3a1b33f55f20a5d151ba967c11838d38afc4f4de | |
parent | e172ceb49be4dc2f34baf01fe1b1761ab1d93a40 (diff) |
[EPG] GUIEPGGridContainer: recalculate grid data asynchronously.
-rw-r--r-- | xbmc/epg/GUIEPGGridContainer.cpp | 51 | ||||
-rw-r--r-- | xbmc/epg/GUIEPGGridContainer.h | 6 | ||||
-rw-r--r-- | xbmc/epg/GUIEPGGridContainerModel.cpp | 9 | ||||
-rw-r--r-- | xbmc/epg/GUIEPGGridContainerModel.h | 4 | ||||
-rw-r--r-- | xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 101 | ||||
-rw-r--r-- | xbmc/pvr/windows/GUIWindowPVRGuide.h | 3 |
6 files changed, 99 insertions, 75 deletions
diff --git a/xbmc/epg/GUIEPGGridContainer.cpp b/xbmc/epg/GUIEPGGridContainer.cpp index 383c66a275..454f3df53a 100644 --- a/xbmc/epg/GUIEPGGridContainer.cpp +++ b/xbmc/epg/GUIEPGGridContainer.cpp @@ -147,6 +147,8 @@ CGUIEPGGridContainer::CGUIEPGGridContainer(const CGUIEPGGridContainer &other) m_channelScrollSpeed = other.m_channelScrollSpeed; m_channelScrollOffset = other.m_channelScrollOffset; m_gridModel = other.m_gridModel; + m_updatedGridModel = other.m_updatedGridModel; + m_outdatedGridModel = other.m_outdatedGridModel; } void CGUIEPGGridContainer::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) @@ -808,7 +810,7 @@ bool CGUIEPGGridContainer::OnMessage(CGUIMessage& message) return true; case GUI_MSG_LABEL_BIND: - UpdateItems(static_cast<CFileItemList *>(message.GetPointer())); + UpdateItems(); return true; case GUI_MSG_REFRESH_LIST: @@ -821,13 +823,13 @@ bool CGUIEPGGridContainer::OnMessage(CGUIMessage& message) return CGUIControl::OnMessage(message); } -void CGUIEPGGridContainer::UpdateItems(CFileItemList *items) +void CGUIEPGGridContainer::UpdateItems() { - if (!items) - return; - CSingleLock lock(m_critSection); + if (!m_updatedGridModel) + return; + /* Safe currently selected epg tag and grid coordinates. Selection shall be restored after update. */ const CEpgInfoTagPtr prevSelectedEpgTag(GetSelectedEpgInfoTag()); const int oldChannelIndex = m_channelOffset + m_channelCursor; @@ -876,9 +878,9 @@ void CGUIEPGGridContainer::UpdateItems(CFileItemList *items) m_lastItem = nullptr; m_lastChannel = nullptr; - m_gridModel->Refresh(items, m_rulerUnit, m_blocksPerPage, m_blockSize); - - UpdateLayout(); + // always use asynchronously precalculated grid data. + m_outdatedGridModel = std::move(m_gridModel); // destructing grid data can be very expensive, thus this will be done asynchronously, not here. + m_gridModel = std::move(m_updatedGridModel); if (prevSelectedEpgTag) { @@ -1648,13 +1650,36 @@ void CGUIEPGGridContainer::GoToNow() SetBlock(PAGE_NOW_OFFSET); } -void CGUIEPGGridContainer::SetStartEnd(CDateTime start, CDateTime end) +void CGUIEPGGridContainer::SetTimelineItems(const std::unique_ptr<CFileItemList> &items, const CDateTime &gridStart, const CDateTime &gridEnd) { - m_gridModel->SetGridStart(CDateTime(start.GetYear(), start.GetMonth(), start.GetDay(), start.GetHour(), start.GetMinute() >= 30 ? 30 : 0, 0)); - m_gridModel->SetGridEnd(CDateTime(end.GetYear(), end.GetMonth(), end.GetDay(), end.GetHour(), end.GetMinute() >= 30 ? 30 : 0, 0)); + int iRulerUnit; + int iBlocksPerPage; + float fBlockSize; + { + CSingleLock lock(m_critSection); + + UpdateLayout(); + iRulerUnit = m_rulerUnit; + iBlocksPerPage = m_blocksPerPage; + fBlockSize = m_blockSize; + } + + std::shared_ptr<CGUIEPGGridContainerModel> oldOutdatedGridModel; + std::shared_ptr<CGUIEPGGridContainerModel> oldUpdatedGridModel; + std::shared_ptr<CGUIEPGGridContainerModel> newUpdatedGridModel(new CGUIEPGGridContainerModel); + // can be very expensive. never call with lock acquired. + newUpdatedGridModel->Refresh(items, gridStart, gridEnd, iRulerUnit, iBlocksPerPage, fBlockSize); + + { + CSingleLock lock(m_critSection); - CLog::Log(LOGDEBUG, "CGUIEPGGridContainer - %s - start=%s end=%s", - __FUNCTION__, m_gridModel->GetGridStart().GetAsLocalizedDateTime(false, true).c_str(), m_gridModel->GetGridEnd().GetAsLocalizedDateTime(false, true).c_str()); + // grid contains CFileItem instances. CFileItem dtor locks global graphics mutex. + // by increasing its refcount make sure, old data are not deleted while we're holding own mutex. + oldOutdatedGridModel = std::move(m_outdatedGridModel); + oldUpdatedGridModel = std::move(m_updatedGridModel); + + m_updatedGridModel = std::move(newUpdatedGridModel); + } } void CGUIEPGGridContainer::GoToChannel(int channelIndex) diff --git a/xbmc/epg/GUIEPGGridContainer.h b/xbmc/epg/GUIEPGGridContainer.h index 6543eeedaf..b24991b408 100644 --- a/xbmc/epg/GUIEPGGridContainer.h +++ b/xbmc/epg/GUIEPGGridContainer.h @@ -76,7 +76,7 @@ namespace EPG void GoToBegin(); void GoToEnd(); void GoToNow(); - void SetStartEnd(CDateTime start, CDateTime end); + void SetTimelineItems(const std::unique_ptr<CFileItemList> &items, const CDateTime &gridStart, const CDateTime &gridEnd); void SetChannel(const PVR::CPVRChannelPtr &channel); void SetChannel(const std::string &channel); void ResetCoordinates(); @@ -140,7 +140,7 @@ namespace EPG void GetProgrammeCacheOffsets(int &cacheBefore, int &cacheAfter); private: - void UpdateItems(CFileItemList *items); + void UpdateItems(); EPG::CEpgInfoTagPtr GetSelectedEpgInfoTag() const; @@ -189,5 +189,7 @@ namespace EPG CCriticalSection m_critSection; std::shared_ptr<CGUIEPGGridContainerModel> m_gridModel; + std::shared_ptr<CGUIEPGGridContainerModel> m_updatedGridModel; + std::shared_ptr<CGUIEPGGridContainerModel> m_outdatedGridModel; }; } diff --git a/xbmc/epg/GUIEPGGridContainerModel.cpp b/xbmc/epg/GUIEPGGridContainerModel.cpp index 390880dd48..fd56206fd8 100644 --- a/xbmc/epg/GUIEPGGridContainerModel.cpp +++ b/xbmc/epg/GUIEPGGridContainerModel.cpp @@ -60,7 +60,7 @@ void CGUIEPGGridContainerModel::Reset() m_epgItemsPtr.clear(); } -void CGUIEPGGridContainerModel::Refresh(CFileItemList *items, int iRulerUnit, int iBlocksPerPage, float fBlockSize) +void CGUIEPGGridContainerModel::Refresh(const std::unique_ptr<CFileItemList> &items, const CDateTime &gridStart, const CDateTime &gridEnd, int iRulerUnit, int iBlocksPerPage, float fBlockSize) { Reset(); @@ -103,12 +103,17 @@ void CGUIEPGGridContainerModel::Refresh(CFileItemList *items, int iRulerUnit, in } /* check for invalid start and end time */ - if (m_gridStart >= m_gridEnd) + if (gridStart >= gridEnd) { // default to start "now minus 30 minutes" and end "start plus one page". m_gridStart = CDateTime::GetCurrentDateTime().GetAsUTCDateTime() - CDateTimeSpan(0, 0, 30, 0); m_gridEnd = m_gridStart + CDateTimeSpan(0, 0, iBlocksPerPage * MINSPERBLOCK, 0); } + else + { + m_gridStart = CDateTime(gridStart.GetYear(), gridStart.GetMonth(), gridStart.GetDay(), gridStart.GetHour(), gridStart.GetMinute() >= 30 ? 30 : 0, 0); + m_gridEnd = CDateTime(gridEnd.GetYear(), gridEnd.GetMonth(), gridEnd.GetDay(), gridEnd.GetHour(), gridEnd.GetMinute() >= 30 ? 30 : 0, 0); + } //////////////////////////////////////////////////////////////////////// // Create ruler items diff --git a/xbmc/epg/GUIEPGGridContainerModel.h b/xbmc/epg/GUIEPGGridContainerModel.h index 9c92f2fef7..cd3a3bd009 100644 --- a/xbmc/epg/GUIEPGGridContainerModel.h +++ b/xbmc/epg/GUIEPGGridContainerModel.h @@ -47,7 +47,7 @@ namespace EPG CGUIEPGGridContainerModel() : m_blocks(0) {} virtual ~CGUIEPGGridContainerModel() { Reset(); } - void Refresh(CFileItemList *items, int iRulerUnit, int iBlocksPerPage, float fBlockSize); + void Refresh(const std::unique_ptr<CFileItemList> &items, const CDateTime &gridStart, const CDateTime &gridEnd, int iRulerUnit, int iBlocksPerPage, float fBlockSize); void SetInvalid(); void FindChannelAndBlockIndex(int channelUid, unsigned int broadcastUid, int eventOffset, int &newChannelIndex, int &newBlockIndex) const; @@ -78,8 +78,6 @@ namespace EPG bool IsZeroGridDuration() const { return (m_gridEnd - m_gridStart) == CDateTimeSpan(0, 0, 0, 0); } const CDateTime &GetGridStart() const { return m_gridStart; } const CDateTime &GetGridEnd() const { return m_gridEnd; } - void SetGridStart(const CDateTime &gridStart) { m_gridStart = gridStart; } - void SetGridEnd(const CDateTime &gridEnd) { m_gridEnd = gridEnd; } private: void FreeItemsMemory(); diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index 72b3648cb4..312ea45743 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -44,10 +44,9 @@ using namespace EPG; CGUIWindowPVRGuide::CGUIWindowPVRGuide(bool bRadio) : CGUIWindowPVRBase(bRadio, bRadio ? WINDOW_RADIO_GUIDE : WINDOW_TV_GUIDE, "MyPVRGuide.xml"), - m_refreshTimelineItemsThread(new CPVRRefreshTimelineItemsThread(this)) + m_refreshTimelineItemsThread(new CPVRRefreshTimelineItemsThread(this)), + m_cachedChannelGroup(new CPVRChannelGroup) { - m_cachedTimeline = std::make_shared<CFileItemList>(); - m_cachedChannelGroup = CPVRChannelGroupPtr(new CPVRChannelGroup); m_bRefreshTimelineItems = false; } @@ -88,7 +87,7 @@ void CGUIWindowPVRGuide::StartRefreshTimelineItemsThread() void CGUIWindowPVRGuide::StopRefreshTimelineItemsThread() { - m_refreshTimelineItemsThread->StopThread(); + m_refreshTimelineItemsThread->StopThread(false); } void CGUIWindowPVRGuide::RegisterObservers(void) @@ -503,72 +502,68 @@ bool CGUIWindowPVRGuide::RefreshTimelineItems() { m_bRefreshTimelineItems = false; - CPVRChannelGroupPtr group = GetGroup(); + CGUIEPGGridContainer* epgGridContainer = dynamic_cast<CGUIEPGGridContainer*>(GetControl(m_viewControl.GetCurrentControl())); + if (epgGridContainer) + { + const CPVRChannelGroupPtr group(GetGroup()); + std::unique_ptr<CFileItemList> timeline(new CFileItemList); - std::shared_ptr<CFileItemList> timeline = std::make_shared<CFileItemList>(); + // can be very expensive. never call with lock acquired. + group->GetEPGAll(*timeline, true); - // can be very expensive. never call with lock aquired. - group->GetEPGAll(*timeline, true); + CDateTime startDate(group->GetFirstEPGDate()); + CDateTime endDate(group->GetLastEPGDate()); + const CDateTime currentDate(CDateTime::GetCurrentDateTime().GetAsUTCDateTime()); - { - CSingleLock lock(m_critSection); + if (!startDate.IsValid()) + startDate = currentDate; - m_newTimeline = timeline; - m_cachedChannelGroup = group; - } + if (!endDate.IsValid() || endDate < startDate) + endDate = startDate; - return true; + // limit start to linger time + const CDateTime maxPastDate(currentDate - CDateTimeSpan(0, 0, g_advancedSettings.m_iEpgLingerTime, 0)); + if (startDate < maxPastDate) + startDate = maxPastDate; + + // can be very expensive. never call with lock acquired. + epgGridContainer->SetTimelineItems(timeline, startDate, endDate); + + { + CSingleLock lock(m_critSection); + + m_newTimeline = std::move(timeline); + m_cachedChannelGroup = group; + } + return true; + } } return false; } void CGUIWindowPVRGuide::GetViewTimelineItems(CFileItemList &items) { - CGUIEPGGridContainer* epgGridContainer = dynamic_cast<CGUIEPGGridContainer*>(GetControl(m_viewControl.GetCurrentControl())); - if (!epgGridContainer) - return; + CSingleLock lock(m_critSection); - CPVRChannelGroupPtr group; + // group change detected reset grid coordinates and refresh grid items + if (!m_bRefreshTimelineItems && *m_cachedChannelGroup != *GetGroup()) { - CSingleLock lock(m_critSection); - - // group change detected reset grid coordinates and refresh grid items - if (!m_bRefreshTimelineItems && *m_cachedChannelGroup != *GetGroup()) - { - epgGridContainer->ResetCoordinates(); - m_bRefreshTimelineItems = true; - RefreshTimelineItems(); - } + CGUIEPGGridContainer* epgGridContainer = dynamic_cast<CGUIEPGGridContainer*>(GetControl(m_viewControl.GetCurrentControl())); + if (!epgGridContainer) + return; - if (m_newTimeline != nullptr) - { - m_cachedTimeline = m_newTimeline; - m_newTimeline.reset(); - } + epgGridContainer->ResetCoordinates(); + m_bRefreshTimelineItems = true; + RefreshTimelineItems(); + } - items.Clear(); + // Note: no need to do anything if no new data available. items always contains previous data. + if (m_newTimeline) + { items.RemoveDiscCache(GetID()); - items.Assign(*m_cachedTimeline, false); - - group = m_cachedChannelGroup; + items.Assign(*m_newTimeline, false); + m_newTimeline.reset(); } - - CDateTime startDate(group->GetFirstEPGDate()); - CDateTime endDate(group->GetLastEPGDate()); - CDateTime currentDate = CDateTime::GetCurrentDateTime().GetAsUTCDateTime(); - - if (!startDate.IsValid()) - startDate = currentDate; - - if (!endDate.IsValid() || endDate < startDate) - endDate = startDate; - - // limit start to linger time - CDateTime maxPastDate = currentDate - CDateTimeSpan(0, 0, g_advancedSettings.m_iEpgLingerTime, 0); - if (startDate < maxPastDate) - startDate = maxPastDate; - - epgGridContainer->SetStartEnd(startDate, endDate); } bool CGUIWindowPVRGuide::OnContextButtonBegin(CFileItem *item, CONTEXT_BUTTON button) diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.h b/xbmc/pvr/windows/GUIWindowPVRGuide.h index 140d3ef850..da5159576f 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.h +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.h @@ -78,9 +78,8 @@ namespace PVR std::unique_ptr<CPVRRefreshTimelineItemsThread> m_refreshTimelineItemsThread; std::atomic_bool m_bRefreshTimelineItems; - std::shared_ptr<CFileItemList> m_cachedTimeline; CPVRChannelGroupPtr m_cachedChannelGroup; - std::shared_ptr<CFileItemList> m_newTimeline; + std::unique_ptr<CFileItemList> m_newTimeline; }; class CPVRRefreshTimelineItemsThread : public CThread |