Fix keymap.
[vuplus_xbmc] / xbmc / GUILargeTextureManager.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "threads/SystemClock.h"
22 #include "GUILargeTextureManager.h"
23 #include "settings/Settings.h"
24 #include "guilib/Texture.h"
25 #include "threads/SingleLock.h"
26 #include "utils/TimeUtils.h"
27 #include "utils/JobManager.h"
28 #include "guilib/GraphicContext.h"
29 #include "utils/log.h"
30 #include "TextureCache.h"
31
32 using namespace std;
33
34
35 CImageLoader::CImageLoader(const CStdString &path, const bool useCache)
36 {
37   m_path = path;
38   m_texture = NULL;
39   m_use_cache = useCache;
40 }
41
42 CImageLoader::~CImageLoader()
43 {
44   delete(m_texture);
45 }
46
47 bool CImageLoader::DoWork()
48 {
49   bool needsChecking = false;
50   CStdString loadPath;
51
52   CStdString texturePath = g_TextureManager.GetTexturePath(m_path);
53   if (m_use_cache)
54     loadPath = CTextureCache::Get().CheckCachedImage(texturePath, true, needsChecking);
55   else
56     loadPath = texturePath;
57
58   if (m_use_cache && loadPath.empty())
59   {
60     // not in our texture cache, so try and load directly and then cache the result
61     loadPath = CTextureCache::Get().CacheImage(texturePath, &m_texture);
62     if (m_texture)
63       return true; // we're done
64   }
65   if (!m_use_cache || !loadPath.empty())
66   {
67     // direct route - load the image
68     unsigned int start = XbmcThreads::SystemClockMillis();
69     m_texture = CBaseTexture::LoadFromFile(loadPath, g_graphicsContext.GetWidth(), g_graphicsContext.GetHeight(), CSettings::Get().GetBool("pictures.useexifrotation"));
70     if (!m_texture)
71       return false;
72     if (XbmcThreads::SystemClockMillis() - start > 100)
73       CLog::Log(LOGDEBUG, "%s - took %u ms to load %s", __FUNCTION__, XbmcThreads::SystemClockMillis() - start, loadPath.c_str());
74
75     if (needsChecking)
76       CTextureCache::Get().BackgroundCacheImage(texturePath);
77   }
78   return true;
79 }
80
81 CGUILargeTextureManager::CLargeTexture::CLargeTexture(const CStdString &path)
82 {
83   m_path = path;
84   m_refCount = 1;
85   m_timeToDelete = 0;
86 }
87
88 CGUILargeTextureManager::CLargeTexture::~CLargeTexture()
89 {
90   assert(m_refCount == 0);
91   m_texture.Free();
92 }
93
94 void CGUILargeTextureManager::CLargeTexture::AddRef()
95 {
96   m_refCount++;
97 }
98
99 bool CGUILargeTextureManager::CLargeTexture::DecrRef(bool deleteImmediately)
100 {
101   assert(m_refCount);
102   m_refCount--;
103   if (m_refCount == 0)
104   {
105     if (deleteImmediately)
106       delete this;
107     else
108       m_timeToDelete = CTimeUtils::GetFrameTime() + TIME_TO_DELETE;
109     return true;
110   }
111   return false;
112 }
113
114 bool CGUILargeTextureManager::CLargeTexture::DeleteIfRequired(bool deleteImmediately)
115 {
116   if (m_refCount == 0 && (deleteImmediately || m_timeToDelete < CTimeUtils::GetFrameTime()))
117   {
118     delete this;
119     return true;
120   }
121   return false;
122 }
123
124 void CGUILargeTextureManager::CLargeTexture::SetTexture(CBaseTexture* texture)
125 {
126   assert(!m_texture.size());
127   if (texture)
128     m_texture.Set(texture, texture->GetWidth(), texture->GetHeight());
129 }
130
131 CGUILargeTextureManager::CGUILargeTextureManager()
132 {
133 }
134
135 CGUILargeTextureManager::~CGUILargeTextureManager()
136 {
137 }
138
139 void CGUILargeTextureManager::CleanupUnusedImages(bool immediately)
140 {
141   CSingleLock lock(m_listSection);
142   // check for items to remove from allocated list, and remove
143   listIterator it = m_allocated.begin();
144   while (it != m_allocated.end())
145   {
146     CLargeTexture *image = *it;
147     if (image->DeleteIfRequired(immediately))
148       it = m_allocated.erase(it);
149     else
150       ++it;
151   }
152 }
153
154 // if available, increment reference count, and return the image.
155 // else, add to the queue list if appropriate.
156 bool CGUILargeTextureManager::GetImage(const CStdString &path, CTextureArray &texture, bool firstRequest, const bool useCache)
157 {
158   CSingleLock lock(m_listSection);
159   for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
160   {
161     CLargeTexture *image = *it;
162     if (image->GetPath() == path)
163     {
164       if (firstRequest)
165         image->AddRef();
166       texture = image->GetTexture();
167       return texture.size() > 0;
168     }
169   }
170
171   if (firstRequest)
172     QueueImage(path, useCache);
173
174   return true;
175 }
176
177 void CGUILargeTextureManager::ReleaseImage(const CStdString &path, bool immediately)
178 {
179   CSingleLock lock(m_listSection);
180   for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
181   {
182     CLargeTexture *image = *it;
183     if (image->GetPath() == path)
184     {
185       if (image->DecrRef(immediately) && immediately)
186         m_allocated.erase(it);
187       return;
188     }
189   }
190   for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
191   {
192     unsigned int id = it->first;
193     CLargeTexture *image = it->second;
194     if (image->GetPath() == path && image->DecrRef(true))
195     {
196       // cancel this job
197       CJobManager::GetInstance().CancelJob(id);
198       m_queued.erase(it);
199       return;
200     }
201   }
202 }
203
204 // queue the image, and start the background loader if necessary
205 void CGUILargeTextureManager::QueueImage(const CStdString &path, bool useCache)
206 {
207   CSingleLock lock(m_listSection);
208   for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
209   {
210     CLargeTexture *image = it->second;
211     if (image->GetPath() == path)
212     {
213       image->AddRef();
214       return; // already queued
215     }
216   }
217
218   // queue the item
219   CLargeTexture *image = new CLargeTexture(path);
220   unsigned int jobID = CJobManager::GetInstance().AddJob(new CImageLoader(path, useCache), this, CJob::PRIORITY_NORMAL);
221   m_queued.push_back(make_pair(jobID, image));
222 }
223
224 void CGUILargeTextureManager::OnJobComplete(unsigned int jobID, bool success, CJob *job)
225 {
226   // see if we still have this job id
227   CSingleLock lock(m_listSection);
228   for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
229   {
230     if (it->first == jobID)
231     { // found our job
232       CImageLoader *loader = (CImageLoader *)job;
233       CLargeTexture *image = it->second;
234       image->SetTexture(loader->m_texture);
235       loader->m_texture = NULL; // we want to keep the texture, and jobs are auto-deleted.
236       m_queued.erase(it);
237       m_allocated.push_back(image);
238       return;
239     }
240   }
241 }
242
243
244