aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Sommerfeld <kai.sommerfeld@gmx.com>2016-04-13 09:20:01 +0200
committerKai Sommerfeld <kai.sommerfeld@gmx.com>2016-04-29 15:57:13 +0200
commitb4dbbb1aefcb78377e78fb9eb14c2c905d634859 (patch)
tree3a1b33f55f20a5d151ba967c11838d38afc4f4de
parente172ceb49be4dc2f34baf01fe1b1761ab1d93a40 (diff)
[EPG] GUIEPGGridContainer: recalculate grid data asynchronously.
-rw-r--r--xbmc/epg/GUIEPGGridContainer.cpp51
-rw-r--r--xbmc/epg/GUIEPGGridContainer.h6
-rw-r--r--xbmc/epg/GUIEPGGridContainerModel.cpp9
-rw-r--r--xbmc/epg/GUIEPGGridContainerModel.h4
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRGuide.cpp101
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRGuide.h3
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