[windows] Fix MAC Address Discovery
[xbmc.git] / xbmc / GUILargeTextureManager.cpp
blob80b762b20e497aa7e7bffa56d6639213c94655e3
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUILargeTextureManager.h"
11 #include "ServiceBroker.h"
12 #include "TextureCache.h"
13 #include "commons/ilog.h"
14 #include "guilib/GUIComponent.h"
15 #include "guilib/Texture.h"
16 #include "utils/JobManager.h"
17 #include "utils/TimeUtils.h"
18 #include "utils/log.h"
19 #include "windowing/GraphicContext.h"
20 #include "windowing/WinSystem.h"
22 #include <cassert>
23 #include <chrono>
24 #include <exception>
25 #include <mutex>
27 CImageLoader::CImageLoader(const std::string& path, const bool useCache)
28 : m_path(path), m_texture(nullptr)
30 m_use_cache = useCache;
33 CImageLoader::~CImageLoader() = default;
35 bool CImageLoader::DoWork()
37 bool needsChecking = false;
38 std::string loadPath;
40 std::string texturePath = CServiceBroker::GetGUI()->GetTextureManager().GetTexturePath(m_path);
41 if (texturePath.empty())
42 return false;
44 if (m_use_cache)
45 loadPath = CServiceBroker::GetTextureCache()->CheckCachedImage(texturePath, needsChecking);
46 else
47 loadPath = texturePath;
49 if (!loadPath.empty())
51 // direct route - load the image
52 auto start = std::chrono::steady_clock::now();
53 m_texture =
54 CTexture::LoadFromFile(loadPath, CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth(),
55 CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight());
57 auto end = std::chrono::steady_clock::now();
58 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
60 if (duration.count() > 100)
61 CLog::Log(LOGDEBUG, "{} - took {} ms to load {}", __FUNCTION__, duration.count(), loadPath);
63 if (m_texture)
65 if (needsChecking)
66 CServiceBroker::GetTextureCache()->BackgroundCacheImage(texturePath);
68 return true;
71 // Fallthrough on failure:
72 CLog::Log(LOGERROR, "{} - Direct texture file loading failed for {}", __FUNCTION__, loadPath);
75 if (!m_use_cache)
76 return false; // We're done
78 // not in our texture cache or it failed to load from it, so try and load directly and then cache the result
79 CServiceBroker::GetTextureCache()->CacheImage(texturePath, &m_texture);
80 return (m_texture != NULL);
83 CGUILargeTextureManager::CLargeTexture::CLargeTexture(const std::string &path):
84 m_path(path)
86 m_refCount = 1;
87 m_timeToDelete = 0;
90 CGUILargeTextureManager::CLargeTexture::~CLargeTexture()
92 assert(m_refCount == 0);
93 m_texture.Free();
96 void CGUILargeTextureManager::CLargeTexture::AddRef()
98 m_refCount++;
101 bool CGUILargeTextureManager::CLargeTexture::DecrRef(bool deleteImmediately)
103 assert(m_refCount);
104 m_refCount--;
105 if (m_refCount == 0)
107 if (deleteImmediately)
108 delete this;
109 else
110 m_timeToDelete = CTimeUtils::GetFrameTime() + TIME_TO_DELETE;
111 return true;
113 return false;
116 bool CGUILargeTextureManager::CLargeTexture::DeleteIfRequired(bool deleteImmediately)
118 if (m_refCount == 0 && (deleteImmediately || m_timeToDelete < CTimeUtils::GetFrameTime()))
120 delete this;
121 return true;
123 return false;
126 void CGUILargeTextureManager::CLargeTexture::SetTexture(std::unique_ptr<CTexture> texture)
128 assert(!m_texture.size());
129 if (texture)
131 const auto width = texture->GetWidth();
132 const auto height = texture->GetHeight();
133 m_texture.Set(std::move(texture), width, height);
137 CGUILargeTextureManager::CGUILargeTextureManager() = default;
139 CGUILargeTextureManager::~CGUILargeTextureManager() = default;
141 void CGUILargeTextureManager::CleanupUnusedImages(bool immediately)
143 std::unique_lock<CCriticalSection> lock(m_listSection);
144 // check for items to remove from allocated list, and remove
145 listIterator it = m_allocated.begin();
146 while (it != m_allocated.end())
148 CLargeTexture *image = *it;
149 if (image->DeleteIfRequired(immediately))
150 it = m_allocated.erase(it);
151 else
152 ++it;
156 // if available, increment reference count, and return the image.
157 // else, add to the queue list if appropriate.
158 bool CGUILargeTextureManager::GetImage(const std::string &path, CTextureArray &texture, bool firstRequest, const bool useCache)
160 std::unique_lock<CCriticalSection> lock(m_listSection);
161 for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
163 CLargeTexture *image = *it;
164 if (image->GetPath() == path)
166 if (firstRequest)
167 image->AddRef();
168 texture = image->GetTexture();
169 return texture.size() > 0;
173 if (firstRequest)
174 QueueImage(path, useCache);
176 return true;
179 void CGUILargeTextureManager::ReleaseImage(const std::string &path, bool immediately)
181 std::unique_lock<CCriticalSection> lock(m_listSection);
182 for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
184 CLargeTexture *image = *it;
185 if (image->GetPath() == path)
187 if (image->DecrRef(immediately) && immediately)
188 m_allocated.erase(it);
189 return;
192 for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
194 unsigned int id = it->first;
195 CLargeTexture *image = it->second;
196 if (image->GetPath() == path && image->DecrRef(true))
198 // cancel this job
199 CServiceBroker::GetJobManager()->CancelJob(id);
200 m_queued.erase(it);
201 return;
206 // queue the image, and start the background loader if necessary
207 void CGUILargeTextureManager::QueueImage(const std::string &path, bool useCache)
209 if (path.empty())
210 return;
212 std::unique_lock<CCriticalSection> lock(m_listSection);
213 for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
215 CLargeTexture *image = it->second;
216 if (image->GetPath() == path)
218 image->AddRef();
219 return; // already queued
223 // queue the item
224 CLargeTexture *image = new CLargeTexture(path);
225 unsigned int jobID = CServiceBroker::GetJobManager()->AddJob(new CImageLoader(path, useCache),
226 this, CJob::PRIORITY_NORMAL);
227 m_queued.emplace_back(jobID, image);
230 void CGUILargeTextureManager::OnJobComplete(unsigned int jobID, bool success, CJob *job)
232 // see if we still have this job id
233 std::unique_lock<CCriticalSection> lock(m_listSection);
234 for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
236 if (it->first == jobID)
237 { // found our job
238 CImageLoader *loader = static_cast<CImageLoader*>(job);
239 CLargeTexture *image = it->second;
240 image->SetTexture(std::move(loader->m_texture));
241 loader->m_texture = NULL; // we want to keep the texture, and jobs are auto-deleted.
242 m_queued.erase(it);
243 m_allocated.push_back(image);
244 return;