VTB: release CVBuffer after it actually has been rendered
[xbmc.git] / xbmc / GUILargeTextureManager.cpp
blob760ab9cc3587ffe3817a47b72996b3bb073a1ead
1 /*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
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.
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/>.
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"
32 #include <cassert>
34 CImageLoader::CImageLoader(const std::string &path, const bool useCache):
35 m_path(path)
37 m_texture = NULL;
38 m_use_cache = useCache;
41 CImageLoader::~CImageLoader()
43 delete(m_texture);
46 bool CImageLoader::DoWork()
48 bool needsChecking = false;
49 std::string loadPath;
51 std::string texturePath = g_TextureManager.GetTexturePath(m_path);
52 if (texturePath.empty())
53 return false;
55 if (m_use_cache)
56 loadPath = CTextureCache::GetInstance().CheckCachedImage(texturePath, needsChecking);
57 else
58 loadPath = texturePath;
60 if (!loadPath.empty())
62 // direct route - load the image
63 unsigned int start = XbmcThreads::SystemClockMillis();
64 m_texture = CBaseTexture::LoadFromFile(loadPath, g_graphicsContext.GetWidth(), g_graphicsContext.GetHeight());
66 if (XbmcThreads::SystemClockMillis() - start > 100)
67 CLog::Log(LOGDEBUG, "%s - took %u ms to load %s", __FUNCTION__, XbmcThreads::SystemClockMillis() - start, loadPath.c_str());
69 if (m_texture)
71 if (needsChecking)
72 CTextureCache::GetInstance().BackgroundCacheImage(texturePath);
74 return true;
77 // Fallthrough on failure:
78 CLog::Log(LOGERROR, "%s - Direct texture file loading failed for %s", __FUNCTION__, loadPath.c_str());
81 if (!m_use_cache)
82 return false; // We're done
84 // not in our texture cache or it failed to load from it, so try and load directly and then cache the result
85 CTextureCache::GetInstance().CacheImage(texturePath, &m_texture);
86 return (m_texture != NULL);
89 CGUILargeTextureManager::CLargeTexture::CLargeTexture(const std::string &path):
90 m_path(path)
92 m_refCount = 1;
93 m_timeToDelete = 0;
96 CGUILargeTextureManager::CLargeTexture::~CLargeTexture()
98 assert(m_refCount == 0);
99 m_texture.Free();
102 void CGUILargeTextureManager::CLargeTexture::AddRef()
104 m_refCount++;
107 bool CGUILargeTextureManager::CLargeTexture::DecrRef(bool deleteImmediately)
109 assert(m_refCount);
110 m_refCount--;
111 if (m_refCount == 0)
113 if (deleteImmediately)
114 delete this;
115 else
116 m_timeToDelete = CTimeUtils::GetFrameTime() + TIME_TO_DELETE;
117 return true;
119 return false;
122 bool CGUILargeTextureManager::CLargeTexture::DeleteIfRequired(bool deleteImmediately)
124 if (m_refCount == 0 && (deleteImmediately || m_timeToDelete < CTimeUtils::GetFrameTime()))
126 delete this;
127 return true;
129 return false;
132 void CGUILargeTextureManager::CLargeTexture::SetTexture(CBaseTexture* texture)
134 assert(!m_texture.size());
135 if (texture)
136 m_texture.Set(texture, texture->GetWidth(), texture->GetHeight());
139 CGUILargeTextureManager::CGUILargeTextureManager()
143 CGUILargeTextureManager::~CGUILargeTextureManager()
147 void CGUILargeTextureManager::CleanupUnusedImages(bool immediately)
149 CSingleLock lock(m_listSection);
150 // check for items to remove from allocated list, and remove
151 listIterator it = m_allocated.begin();
152 while (it != m_allocated.end())
154 CLargeTexture *image = *it;
155 if (image->DeleteIfRequired(immediately))
156 it = m_allocated.erase(it);
157 else
158 ++it;
162 // if available, increment reference count, and return the image.
163 // else, add to the queue list if appropriate.
164 bool CGUILargeTextureManager::GetImage(const std::string &path, CTextureArray &texture, bool firstRequest, const bool useCache)
166 CSingleLock lock(m_listSection);
167 for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
169 CLargeTexture *image = *it;
170 if (image->GetPath() == path)
172 if (firstRequest)
173 image->AddRef();
174 texture = image->GetTexture();
175 return texture.size() > 0;
179 if (firstRequest)
180 QueueImage(path, useCache);
182 return true;
185 void CGUILargeTextureManager::ReleaseImage(const std::string &path, bool immediately)
187 CSingleLock lock(m_listSection);
188 for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
190 CLargeTexture *image = *it;
191 if (image->GetPath() == path)
193 if (image->DecrRef(immediately) && immediately)
194 m_allocated.erase(it);
195 return;
198 for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
200 unsigned int id = it->first;
201 CLargeTexture *image = it->second;
202 if (image->GetPath() == path && image->DecrRef(true))
204 // cancel this job
205 CJobManager::GetInstance().CancelJob(id);
206 m_queued.erase(it);
207 return;
212 // queue the image, and start the background loader if necessary
213 void CGUILargeTextureManager::QueueImage(const std::string &path, bool useCache)
215 if (path.empty())
216 return;
218 CSingleLock lock(m_listSection);
219 for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
221 CLargeTexture *image = it->second;
222 if (image->GetPath() == path)
224 image->AddRef();
225 return; // already queued
229 // queue the item
230 CLargeTexture *image = new CLargeTexture(path);
231 unsigned int jobID = CJobManager::GetInstance().AddJob(new CImageLoader(path, useCache), this, CJob::PRIORITY_NORMAL);
232 m_queued.push_back(std::make_pair(jobID, image));
235 void CGUILargeTextureManager::OnJobComplete(unsigned int jobID, bool success, CJob *job)
237 // see if we still have this job id
238 CSingleLock lock(m_listSection);
239 for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
241 if (it->first == jobID)
242 { // found our job
243 CImageLoader *loader = (CImageLoader *)job;
244 CLargeTexture *image = it->second;
245 image->SetTexture(loader->m_texture);
246 loader->m_texture = NULL; // we want to keep the texture, and jobs are auto-deleted.
247 m_queued.erase(it);
248 m_allocated.push_back(image);
249 return;