2 * Copyright (C) 2005-2013 Team XBMC
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)
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"
34 CImageLoader::CImageLoader(const std::string
&path
, const bool useCache
):
38 m_use_cache
= useCache
;
41 CImageLoader::~CImageLoader()
46 bool CImageLoader::DoWork()
48 bool needsChecking
= false;
51 std::string texturePath
= g_TextureManager
.GetTexturePath(m_path
);
52 if (texturePath
.empty())
56 loadPath
= CTextureCache::GetInstance().CheckCachedImage(texturePath
, needsChecking
);
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());
72 CTextureCache::GetInstance().BackgroundCacheImage(texturePath
);
77 // Fallthrough on failure:
78 CLog::Log(LOGERROR
, "%s - Direct texture file loading failed for %s", __FUNCTION__
, loadPath
.c_str());
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
):
96 CGUILargeTextureManager::CLargeTexture::~CLargeTexture()
98 assert(m_refCount
== 0);
102 void CGUILargeTextureManager::CLargeTexture::AddRef()
107 bool CGUILargeTextureManager::CLargeTexture::DecrRef(bool deleteImmediately
)
113 if (deleteImmediately
)
116 m_timeToDelete
= CTimeUtils::GetFrameTime() + TIME_TO_DELETE
;
122 bool CGUILargeTextureManager::CLargeTexture::DeleteIfRequired(bool deleteImmediately
)
124 if (m_refCount
== 0 && (deleteImmediately
|| m_timeToDelete
< CTimeUtils::GetFrameTime()))
132 void CGUILargeTextureManager::CLargeTexture::SetTexture(CBaseTexture
* texture
)
134 assert(!m_texture
.size());
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
);
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
)
174 texture
= image
->GetTexture();
175 return texture
.size() > 0;
180 QueueImage(path
, useCache
);
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
);
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))
205 CJobManager::GetInstance().CancelJob(id
);
212 // queue the image, and start the background loader if necessary
213 void CGUILargeTextureManager::QueueImage(const std::string
&path
, bool useCache
)
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
)
225 return; // already queued
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
)
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.
248 m_allocated
.push_back(image
);