[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / guilib / GUIImage.cpp
blob9b7ad23de55a72c13837f35d86f02b957b994e99
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 "GUIImage.h"
11 #include "GUIMessage.h"
12 #include "utils/log.h"
14 #include <cassert>
16 using namespace KODI::GUILIB;
18 CGUIImage::CGUIImage(int parentID,
19 int controlID,
20 float posX,
21 float posY,
22 float width,
23 float height,
24 const CTextureInfo& texture)
25 : CGUIControl(parentID, controlID, posX, posY, width, height),
26 m_texture(CGUITexture::CreateTexture(posX, posY, width, height, texture))
28 m_crossFadeTime = 0;
29 m_currentFadeTime = 0;
30 m_lastRenderTime = 0;
31 ControlType = GUICONTROL_IMAGE;
32 m_bDynamicResourceAlloc=false;
35 CGUIImage::CGUIImage(const CGUIImage& left)
36 : CGUIControl(left),
37 m_image(left.m_image),
38 m_info(left.m_info),
39 m_texture(left.m_texture->Clone()),
40 m_fadingTextures(),
41 m_currentTexture(),
42 m_currentFallback()
44 m_crossFadeTime = left.m_crossFadeTime;
45 // defaults
46 m_currentFadeTime = 0;
47 m_lastRenderTime = 0;
48 ControlType = GUICONTROL_IMAGE;
49 m_bDynamicResourceAlloc=false;
52 CGUIImage::~CGUIImage(void) = default;
54 void CGUIImage::UpdateVisibility(const CGUIListItem *item)
56 CGUIControl::UpdateVisibility(item);
58 // now that we've checked for conditional info, we can
59 // check for allocation
60 AllocateOnDemand();
63 void CGUIImage::UpdateDiffuseColor(const CGUIListItem* item)
65 if (m_texture->SetDiffuseColor(m_diffuseColor, item))
67 MarkDirtyRegion();
71 void CGUIImage::UpdateInfo(const CGUIListItem *item)
73 // The texture may also depend on info conditions. Update the diffuse color in that case.
74 if (m_texture->GetDiffuseColor().HasInfo())
75 UpdateDiffuseColor(item);
77 if (m_info.IsConstant())
78 return; // nothing to do
80 // don't allow image to change while animating out
81 if (HasProcessed() && IsAnimating(ANIM_TYPE_HIDDEN) && !IsVisibleFromSkin())
82 return;
84 if (item)
85 SetFileName(m_info.GetItemLabel(item, true, &m_currentFallback));
86 else
87 SetFileName(m_info.GetLabel(m_parentID, true, &m_currentFallback));
90 void CGUIImage::AllocateOnDemand()
92 // if we're hidden, we can free our resources and return
93 if (!IsVisible() && m_visible != DELAYED)
95 if (m_bDynamicResourceAlloc && m_texture->IsAllocated())
96 FreeResourcesButNotAnims();
97 return;
100 // either visible or delayed - we need the resources allocated in either case
101 if (!m_texture->IsAllocated())
102 AllocResources();
105 void CGUIImage::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
107 // check whether our image failed to allocate, and if so drop back to the fallback image
108 if (m_texture->FailedToAlloc() && m_texture->GetFileName() != m_info.GetFallback())
110 if (!m_currentFallback.empty() && m_texture->GetFileName() != m_currentFallback)
111 m_texture->SetFileName(m_currentFallback);
112 else
113 m_texture->SetFileName(m_info.GetFallback());
116 if (m_crossFadeTime)
118 // make sure our texture has started allocating
119 if (m_texture->AllocResources())
120 MarkDirtyRegion();
122 // compute the frame time
123 unsigned int frameTime = 0;
124 if (m_lastRenderTime)
125 frameTime = currentTime - m_lastRenderTime;
126 if (!frameTime)
127 frameTime = (unsigned int)(1000 / CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS());
128 m_lastRenderTime = currentTime;
130 if (m_fadingTextures.size()) // have some fading images
131 { // anything other than the last old texture needs to be faded out as per usual
132 for (std::vector<CFadingTexture *>::iterator i = m_fadingTextures.begin(); i != m_fadingTextures.end() - 1;)
134 if (!ProcessFading(*i, frameTime, currentTime))
135 i = m_fadingTextures.erase(i);
136 else
137 ++i;
140 if (m_texture->ReadyToRender() || m_texture->GetFileName().empty())
141 { // fade out the last one as well
142 if (!ProcessFading(m_fadingTextures[m_fadingTextures.size() - 1], frameTime, currentTime))
143 m_fadingTextures.erase(m_fadingTextures.end() - 1);
145 else
146 { // keep the last one fading in
147 CFadingTexture *texture = m_fadingTextures[m_fadingTextures.size() - 1];
148 texture->m_fadeTime += frameTime;
149 if (texture->m_fadeTime > m_crossFadeTime)
150 texture->m_fadeTime = m_crossFadeTime;
152 if (texture->m_texture->SetAlpha(GetFadeLevel(texture->m_fadeTime)))
153 MarkDirtyRegion();
154 if (texture->m_texture->SetDiffuseColor(m_diffuseColor))
155 MarkDirtyRegion();
156 if (texture->m_texture->Process(currentTime))
157 MarkDirtyRegion();
161 if (m_texture->ReadyToRender() || m_texture->GetFileName().empty())
162 { // fade the new one in
163 m_currentFadeTime += frameTime;
164 if (m_currentFadeTime > m_crossFadeTime || frameTime == 0) // for if we allocate straight away on creation
165 m_currentFadeTime = m_crossFadeTime;
167 if (m_texture->SetAlpha(GetFadeLevel(m_currentFadeTime)))
168 MarkDirtyRegion();
171 if (!m_texture->GetDiffuseColor().HasInfo())
172 UpdateDiffuseColor(nullptr);
174 if (m_texture->Process(currentTime))
175 MarkDirtyRegion();
177 CGUIControl::Process(currentTime, dirtyregions);
180 void CGUIImage::Render()
182 if (!IsVisible()) return;
184 for (auto& itr : m_fadingTextures)
185 itr->m_texture->Render();
187 m_texture->Render();
189 CGUIControl::Render();
192 bool CGUIImage::ProcessFading(CGUIImage::CFadingTexture *texture, unsigned int frameTime, unsigned int currentTime)
194 assert(texture);
195 if (texture->m_fadeTime <= frameTime)
196 { // time to kill off the texture
197 MarkDirtyRegion();
198 delete texture;
199 return false;
201 // render this texture
202 texture->m_fadeTime -= frameTime;
204 if (texture->m_texture->SetAlpha(GetFadeLevel(texture->m_fadeTime)))
205 MarkDirtyRegion();
206 if (texture->m_texture->SetDiffuseColor(m_diffuseColor))
207 MarkDirtyRegion();
208 if (texture->m_texture->Process(currentTime))
209 MarkDirtyRegion();
211 return true;
214 bool CGUIImage::OnAction(const CAction &action)
216 return false;
219 bool CGUIImage::OnMessage(CGUIMessage& message)
221 if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
223 if (!m_info.IsConstant())
224 FreeTextures(true); // true as we want to free the texture immediately
225 return true;
227 else if (message.GetMessage() == GUI_MSG_SET_FILENAME)
229 SetFileName(message.GetLabel());
230 return true;
232 else if (message.GetMessage() == GUI_MSG_GET_FILENAME)
234 message.SetLabel(GetFileName());
235 return true;
237 return CGUIControl::OnMessage(message);
240 void CGUIImage::AllocResources()
242 if (m_texture->GetFileName().empty())
243 return;
245 CGUIControl::AllocResources();
246 m_texture->AllocResources();
249 void CGUIImage::FreeTextures(bool immediately /* = false */)
251 m_texture->FreeResources(immediately);
252 for (unsigned int i = 0; i < m_fadingTextures.size(); i++)
253 delete m_fadingTextures[i];
254 m_fadingTextures.clear();
255 m_currentTexture.clear();
256 if (!m_info.IsConstant()) // constant textures never change
257 m_texture->SetFileName("");
260 void CGUIImage::FreeResources(bool immediately)
262 FreeTextures(immediately);
263 CGUIControl::FreeResources(immediately);
266 void CGUIImage::SetInvalid()
268 m_texture->SetInvalid();
269 CGUIControl::SetInvalid();
272 // WORKAROUND - we are currently resetting all animations when this is called, which shouldn't be the case
273 // see CGUIControl::FreeResources() - this needs remedying.
274 void CGUIImage::FreeResourcesButNotAnims()
276 FreeTextures();
277 m_bAllocated=false;
278 m_hasProcessed = false;
281 void CGUIImage::DynamicResourceAlloc(bool bOnOff)
283 m_bDynamicResourceAlloc = bOnOff;
284 m_texture->DynamicResourceAlloc(bOnOff);
285 CGUIControl::DynamicResourceAlloc(bOnOff);
288 bool CGUIImage::CanFocus() const
290 return false;
293 float CGUIImage::GetTextureWidth() const
295 return m_texture->GetTextureWidth();
298 float CGUIImage::GetTextureHeight() const
300 return m_texture->GetTextureHeight();
303 CRect CGUIImage::CalcRenderRegion() const
305 CRect region = m_texture->GetRenderRect();
307 for (const auto& itr : m_fadingTextures)
308 region.Union(itr->m_texture->GetRenderRect());
310 return CGUIControl::CalcRenderRegion().Intersect(region);
313 const std::string &CGUIImage::GetFileName() const
315 return m_texture->GetFileName();
318 void CGUIImage::SetAspectRatio(const CAspectRatio &aspect)
320 m_texture->SetAspectRatio(aspect);
323 void CGUIImage::SetCrossFade(unsigned int time)
325 m_crossFadeTime = time;
326 if (!m_crossFadeTime && m_texture->IsLazyLoaded() && !m_info.GetFallback().empty())
327 m_crossFadeTime = 1;
330 void CGUIImage::SetFileName(const std::string& strFileName, bool setConstant, const bool useCache)
332 if (setConstant)
333 m_info.SetLabel(strFileName, "", GetParentID());
335 // Set whether or not to use cache
336 m_texture->SetUseCache(useCache);
338 if (m_crossFadeTime)
340 // set filename on the next texture
341 if (m_currentTexture == strFileName)
342 return; // nothing to do - we already have this image
344 if (m_texture->ReadyToRender() || m_texture->GetFileName().empty())
345 { // save the current image
346 m_fadingTextures.push_back(new CFadingTexture(m_texture.get(), m_currentFadeTime));
347 MarkDirtyRegion();
349 m_currentFadeTime = 0;
351 if (m_currentTexture != strFileName)
352 { // texture is changing - attempt to load it, and save the name in m_currentTexture.
353 // we'll check whether it loaded or not in Render()
354 m_currentTexture = strFileName;
355 if (m_texture->SetFileName(m_currentTexture))
356 MarkDirtyRegion();
360 #ifdef _DEBUG
361 void CGUIImage::DumpTextureUse()
363 if (m_texture->IsAllocated())
365 if (GetID())
366 CLog::Log(LOGDEBUG, "Image control {} using texture {}", GetID(), m_texture->GetFileName());
367 else
368 CLog::Log(LOGDEBUG, "Using texture {}", m_texture->GetFileName());
371 #endif
373 void CGUIImage::SetWidth(float width)
375 m_texture->SetWidth(width);
376 CGUIControl::SetWidth(m_texture->GetWidth());
379 void CGUIImage::SetHeight(float height)
381 m_texture->SetHeight(height);
382 CGUIControl::SetHeight(m_texture->GetHeight());
385 void CGUIImage::SetPosition(float posX, float posY)
387 m_texture->SetPosition(posX, posY);
388 CGUIControl::SetPosition(posX, posY);
391 void CGUIImage::SetInfo(const GUIINFO::CGUIInfoLabel &info)
393 m_info = info;
394 // a constant image never needs updating
395 if (m_info.IsConstant())
396 m_texture->SetFileName(m_info.GetLabel(0));
399 unsigned char CGUIImage::GetFadeLevel(unsigned int time) const
401 float amount = (float)time / m_crossFadeTime;
402 // we want a semi-transparent image, so we need to use a more complicated
403 // fade technique. Assuming a black background (not generally true, but still...)
404 // we have
405 // b(t) = [a - b(1-t)*a] / a*(1-b(1-t)*a),
406 // where a = alpha, and b(t):[0,1] -> [0,1] is the blend function.
407 // solving, we get
408 // b(t) = [1 - (1-a)^t] / a
409 const float alpha = 0.7f;
410 return (unsigned char)(255.0f * (1 - pow(1-alpha, amount))/alpha);
413 std::string CGUIImage::GetDescription(void) const
415 return GetFileName();