[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / windowing / GraphicContext.cpp
blobebaec5b715a6a9ec0446a289c042fbe4b25a1255
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 "GraphicContext.h"
11 #include "ServiceBroker.h"
12 #include "WinSystem.h"
13 #include "application/ApplicationComponents.h"
14 #include "application/ApplicationPlayer.h"
15 #include "guilib/GUIComponent.h"
16 #include "guilib/GUIWindowManager.h"
17 #include "guilib/TextureManager.h"
18 #include "guilib/gui3d.h"
19 #include "input/InputManager.h"
20 #include "messaging/ApplicationMessenger.h"
21 #include "rendering/RenderSystem.h"
22 #include "settings/AdvancedSettings.h"
23 #include "settings/DisplaySettings.h"
24 #include "settings/Settings.h"
25 #include "settings/SettingsComponent.h"
26 #include "settings/lib/Setting.h"
27 #include "utils/log.h"
29 #include <cassert>
30 #include <mutex>
32 CGraphicContext::CGraphicContext() = default;
33 CGraphicContext::~CGraphicContext() = default;
35 void CGraphicContext::SetOrigin(float x, float y)
37 if (!m_origins.empty())
38 m_origins.push(CPoint(x,y) + m_origins.top());
39 else
40 m_origins.emplace(x, y);
42 AddTransform(TransformMatrix::CreateTranslation(x, y));
45 void CGraphicContext::RestoreOrigin()
47 if (!m_origins.empty())
48 m_origins.pop();
49 RemoveTransform();
52 // add a new clip region, intersecting with the previous clip region.
53 bool CGraphicContext::SetClipRegion(float x, float y, float w, float h)
54 { // transform from our origin
55 CPoint origin;
56 if (!m_origins.empty())
57 origin = m_origins.top();
59 // ok, now intersect with our old clip region
60 CRect rect(x, y, x + w, y + h);
61 rect += origin;
62 if (!m_clipRegions.empty())
64 // intersect with original clip region
65 rect.Intersect(m_clipRegions.top());
68 if (rect.IsEmpty())
69 return false;
71 m_clipRegions.push(rect);
73 // here we could set the hardware clipping, if applicable
74 return true;
77 void CGraphicContext::RestoreClipRegion()
79 if (!m_clipRegions.empty())
80 m_clipRegions.pop();
82 // here we could reset the hardware clipping, if applicable
85 void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
87 // this is the software clipping routine. If the graphics hardware is set to do the clipping
88 // (eg via SetClipPlane in D3D for instance) then this routine is unneeded.
89 if (!m_clipRegions.empty())
91 // take a copy of the vertex rectangle and intersect
92 // it with our clip region (moved to the same coordinate system)
93 CRect clipRegion(m_clipRegions.top());
94 if (!m_origins.empty())
95 clipRegion -= m_origins.top();
96 CRect original(vertex);
97 vertex.Intersect(clipRegion);
98 // and use the original to compute the texture coordinates
99 if (original != vertex)
101 float scaleX = texture.Width() / original.Width();
102 float scaleY = texture.Height() / original.Height();
103 texture.x1 += (vertex.x1 - original.x1) * scaleX;
104 texture.y1 += (vertex.y1 - original.y1) * scaleY;
105 texture.x2 += (vertex.x2 - original.x2) * scaleX;
106 texture.y2 += (vertex.y2 - original.y2) * scaleY;
107 if (texture2)
109 scaleX = texture2->Width() / original.Width();
110 scaleY = texture2->Height() / original.Height();
111 texture2->x1 += (vertex.x1 - original.x1) * scaleX;
112 texture2->y1 += (vertex.y1 - original.y1) * scaleY;
113 texture2->x2 += (vertex.x2 - original.x2) * scaleX;
114 texture2->y2 += (vertex.y2 - original.y2) * scaleY;
120 CRect CGraphicContext::GetClipRegion()
122 if (m_clipRegions.empty())
123 return CRect(0, 0, m_iScreenWidth, m_iScreenHeight);
124 CRect clipRegion(m_clipRegions.top());
125 if (!m_origins.empty())
126 clipRegion -= m_origins.top();
127 return clipRegion;
130 void CGraphicContext::AddGUITransform()
132 m_transforms.push(m_finalTransform);
133 m_finalTransform = m_guiTransform;
136 TransformMatrix CGraphicContext::AddTransform(const TransformMatrix &matrix)
138 m_transforms.push(m_finalTransform);
139 m_finalTransform.matrix *= matrix;
140 return m_finalTransform.matrix;
143 void CGraphicContext::SetTransform(const TransformMatrix &matrix)
145 m_transforms.push(m_finalTransform);
146 m_finalTransform.matrix = matrix;
149 void CGraphicContext::SetTransform(const TransformMatrix &matrix, float scaleX, float scaleY)
151 m_transforms.push(m_finalTransform);
152 m_finalTransform.matrix = matrix;
153 m_finalTransform.scaleX = scaleX;
154 m_finalTransform.scaleY = scaleY;
157 void CGraphicContext::RemoveTransform()
159 if (!m_transforms.empty())
161 m_finalTransform = m_transforms.top();
162 m_transforms.pop();
166 bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */)
168 // transform coordinates - we may have a rotation which changes the positioning of the
169 // minimal and maximal viewport extents. We currently go to the maximal extent.
170 float x[4], y[4];
171 x[0] = x[3] = fx;
172 x[1] = x[2] = fx + fwidth;
173 y[0] = y[1] = fy;
174 y[2] = y[3] = fy + fheight;
175 float minX = (float)m_iScreenWidth;
176 float maxX = 0;
177 float minY = (float)m_iScreenHeight;
178 float maxY = 0;
179 for (int i = 0; i < 4; i++)
181 float z = 0;
182 ScaleFinalCoords(x[i], y[i], z);
183 if (x[i] < minX) minX = x[i];
184 if (x[i] > maxX) maxX = x[i];
185 if (y[i] < minY) minY = y[i];
186 if (y[i] > maxY) maxY = y[i];
189 int newLeft = (int)(minX + 0.5f);
190 int newTop = (int)(minY + 0.5f);
191 int newRight = (int)(maxX + 0.5f);
192 int newBottom = (int)(maxY + 0.5f);
193 if (intersectPrevious)
195 CRect oldviewport = m_viewStack.top();
196 // do the intersection
197 int oldLeft = (int)oldviewport.x1;
198 int oldTop = (int)oldviewport.y1;
199 int oldRight = (int)oldviewport.x2;
200 int oldBottom = (int)oldviewport.y2;
201 if (newLeft >= oldRight || newTop >= oldBottom || newRight <= oldLeft || newBottom <= oldTop)
202 { // empty intersection - return false to indicate no rendering should occur
203 return false;
205 // ok, they intersect, do the intersection
206 if (newLeft < oldLeft) newLeft = oldLeft;
207 if (newTop < oldTop) newTop = oldTop;
208 if (newRight > oldRight) newRight = oldRight;
209 if (newBottom > oldBottom) newBottom = oldBottom;
211 // check range against screen size
212 if (newRight <= 0 || newBottom <= 0 ||
213 newTop >= m_iScreenHeight || newLeft >= m_iScreenWidth ||
214 newLeft >= newRight || newTop >= newBottom)
215 { // no intersection with the screen
216 return false;
218 // intersection with the screen
219 if (newLeft < 0) newLeft = 0;
220 if (newTop < 0) newTop = 0;
221 if (newRight > m_iScreenWidth) newRight = m_iScreenWidth;
222 if (newBottom > m_iScreenHeight) newBottom = m_iScreenHeight;
224 assert(newLeft < newRight);
225 assert(newTop < newBottom);
227 CRect newviewport((float)newLeft, (float)newTop, (float)newRight, (float)newBottom);
229 m_viewStack.push(newviewport);
231 newviewport = StereoCorrection(newviewport);
232 CServiceBroker::GetRenderSystem()->SetViewPort(newviewport);
235 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
236 return true;
239 void CGraphicContext::RestoreViewPort()
241 if (m_viewStack.size() <= 1) return;
243 m_viewStack.pop();
244 CRect viewport = StereoCorrection(m_viewStack.top());
245 CServiceBroker::GetRenderSystem()->SetViewPort(viewport);
247 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
250 CPoint CGraphicContext::StereoCorrection(const CPoint &point) const
252 CPoint res(point);
254 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
256 const RESOLUTION_INFO info = GetResInfo();
258 if(m_stereoView == RENDER_STEREO_VIEW_RIGHT)
259 res.y += info.iHeight + info.iBlanking;
261 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
263 const RESOLUTION_INFO info = GetResInfo();
265 if(m_stereoView == RENDER_STEREO_VIEW_RIGHT)
266 res.x += info.iWidth + info.iBlanking;
268 return res;
271 CRect CGraphicContext::StereoCorrection(const CRect &rect) const
273 CRect res(StereoCorrection(rect.P1())
274 , StereoCorrection(rect.P2()));
275 return res;
278 void CGraphicContext::SetScissors(const CRect &rect)
280 m_scissors = rect;
281 m_scissors.Intersect(CRect(0,0,(float)m_iScreenWidth, (float)m_iScreenHeight));
282 CServiceBroker::GetRenderSystem()->SetScissors(StereoCorrection(m_scissors));
285 const CRect &CGraphicContext::GetScissors() const
287 return m_scissors;
290 void CGraphicContext::ResetScissors()
292 m_scissors.SetRect(0, 0, (float)m_iScreenWidth, (float)m_iScreenHeight);
293 CServiceBroker::GetRenderSystem()->SetScissors(StereoCorrection(m_scissors));
296 const CRect CGraphicContext::GetViewWindow() const
298 if (m_bCalibrating || m_bFullScreenVideo)
300 CRect rect;
301 RESOLUTION_INFO info = GetResInfo();
302 rect.x1 = (float)info.Overscan.left;
303 rect.y1 = (float)info.Overscan.top;
304 rect.x2 = (float)info.Overscan.right;
305 rect.y2 = (float)info.Overscan.bottom;
306 return rect;
308 return m_videoRect;
311 void CGraphicContext::SetViewWindow(float left, float top, float right, float bottom)
313 m_videoRect.x1 = ScaleFinalXCoord(left, top);
314 m_videoRect.y1 = ScaleFinalYCoord(left, top);
315 m_videoRect.x2 = ScaleFinalXCoord(right, bottom);
316 m_videoRect.y2 = ScaleFinalYCoord(right, bottom);
319 void CGraphicContext::SetFullScreenVideo(bool bOnOff)
321 std::unique_lock<CCriticalSection> lock(*this);
323 m_bFullScreenVideo = bOnOff;
325 if (m_bFullScreenRoot)
327 bool bTriggerUpdateRes = false;
328 auto& components = CServiceBroker::GetAppComponents();
329 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
330 if (m_bFullScreenVideo)
331 bTriggerUpdateRes = true;
332 else
334 bool allowDesktopRes = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) == ADJUST_REFRESHRATE_ALWAYS;
335 if (!allowDesktopRes)
337 if (appPlayer->IsPlayingVideo())
338 bTriggerUpdateRes = true;
342 bool allowResolutionChangeOnStop = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_ON_START;
343 RESOLUTION targetResolutionOnStop = RES_DESKTOP;
344 if (bTriggerUpdateRes)
345 appPlayer->TriggerUpdateResolution();
346 else if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP)
348 targetResolutionOnStop = CDisplaySettings::GetInstance().GetCurrentResolution();
351 if (allowResolutionChangeOnStop && !bTriggerUpdateRes)
353 SetVideoResolution(targetResolutionOnStop, false);
356 else
357 SetVideoResolution(RES_WINDOW, false);
360 bool CGraphicContext::IsFullScreenVideo() const
362 return m_bFullScreenVideo;
365 bool CGraphicContext::IsCalibrating() const
367 return m_bCalibrating;
370 void CGraphicContext::SetCalibrating(bool bOnOff)
372 m_bCalibrating = bOnOff;
375 bool CGraphicContext::IsValidResolution(RESOLUTION res)
377 if (res >= RES_WINDOW && (size_t) res < CDisplaySettings::GetInstance().ResolutionInfoSize())
379 return true;
382 return false;
385 // call SetVideoResolutionInternal and ensure its done from mainthread
386 void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate)
388 if (CServiceBroker::GetAppMessenger()->IsProcessThread())
390 SetVideoResolutionInternal(res, forceUpdate);
392 else
394 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_SETVIDEORESOLUTION, res, forceUpdate ? 1 : 0);
398 void CGraphicContext::SetVideoResolutionInternal(RESOLUTION res, bool forceUpdate)
400 RESOLUTION lastRes = m_Resolution;
402 // If the user asked us to guess, go with desktop
403 if (!IsValidResolution(res))
405 res = RES_DESKTOP;
408 // If we are switching to the same resolution and same window/full-screen, no need to do anything
409 if (!forceUpdate && res == lastRes && m_bFullScreenRoot == CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen)
411 return;
414 if (res >= RES_DESKTOP)
416 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = true;
417 m_bFullScreenRoot = true;
419 else
421 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = false;
422 m_bFullScreenRoot = false;
425 std::unique_lock<CCriticalSection> lock(*this);
427 // FIXME Wayland windowing needs some way to "deny" resolution updates since what Kodi
428 // requests might not get actually set by the compositor.
429 // So in theory, m_iScreenWidth etc. would not need to be updated at all before the
430 // change is confirmed.
431 // But other windowing code expects these variables to be already set when
432 // SetFullScreen() is called, so set them anyway and remember the old values.
433 int origScreenWidth = m_iScreenWidth;
434 int origScreenHeight = m_iScreenHeight;
435 float origFPSOverride = m_fFPSOverride;
437 UpdateInternalStateWithResolution(res);
438 RESOLUTION_INFO info_org = CDisplaySettings::GetInstance().GetResolutionInfo(res);
440 bool switched = false;
441 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen)
443 #if defined (TARGET_DARWIN) || defined (TARGET_WINDOWS)
444 bool blankOtherDisplays = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS);
445 switched = CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org, blankOtherDisplays);
446 #else
447 switched = CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org, false);
448 #endif
450 else if (lastRes >= RES_DESKTOP )
451 switched = CServiceBroker::GetWinSystem()->SetFullScreen(false, info_org, false);
452 else
453 switched = CServiceBroker::GetWinSystem()->ResizeWindow(info_org.iWidth, info_org.iHeight, -1, -1);
455 if (switched)
457 m_scissors.SetRect(0, 0, (float)m_iScreenWidth, (float)m_iScreenHeight);
459 // make sure all stereo stuff are correctly setup
460 SetStereoView(RENDER_STEREO_VIEW_OFF);
462 // update anyone that relies on sizing information
463 CServiceBroker::GetInputManager().SetMouseResolution(info_org.iWidth, info_org.iHeight, 1, 1);
465 CGUIComponent *gui = CServiceBroker::GetGUI();
466 if (gui)
467 gui->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
469 else
471 // Reset old state
472 m_iScreenWidth = origScreenWidth;
473 m_iScreenHeight = origScreenHeight;
474 m_fFPSOverride = origFPSOverride;
475 if (IsValidResolution(lastRes))
477 m_Resolution = lastRes;
479 else
481 // FIXME Resolution has become invalid
482 // This happens e.g. when switching monitors and the new monitor has fewer
483 // resolutions than the old one. Fall back to RES_DESKTOP and hope that
484 // the real resolution is set soon.
485 // Again, must be fixed as part of a greater refactor.
486 m_Resolution = RES_DESKTOP;
491 void CGraphicContext::ApplyVideoResolution(RESOLUTION res)
493 if (!IsValidResolution(res))
495 CLog::LogF(LOGWARNING, "Asked to apply invalid resolution {}, falling back to RES_DESKTOP",
496 res);
497 res = RES_DESKTOP;
500 if (res >= RES_DESKTOP)
502 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = true;
503 m_bFullScreenRoot = true;
505 else
507 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = false;
508 m_bFullScreenRoot = false;
511 std::unique_lock<CCriticalSection> lock(*this);
513 UpdateInternalStateWithResolution(res);
515 m_scissors.SetRect(0, 0, (float)m_iScreenWidth, (float)m_iScreenHeight);
517 // make sure all stereo stuff are correctly setup
518 SetStereoView(RENDER_STEREO_VIEW_OFF);
520 // update anyone that relies on sizing information
521 RESOLUTION_INFO info_org = CDisplaySettings::GetInstance().GetResolutionInfo(res);
522 CServiceBroker::GetInputManager().SetMouseResolution(info_org.iWidth, info_org.iHeight, 1, 1);
523 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
526 void CGraphicContext::UpdateInternalStateWithResolution(RESOLUTION res)
528 RESOLUTION_INFO info_mod = GetResInfo(res);
530 m_iScreenWidth = info_mod.iWidth;
531 m_iScreenHeight = info_mod.iHeight;
532 m_Resolution = res;
533 m_fFPSOverride = 0;
536 void CGraphicContext::ApplyModeChange(RESOLUTION res)
538 ApplyVideoResolution(res);
539 CServiceBroker::GetWinSystem()->FinishModeChange(res);
542 void CGraphicContext::ApplyWindowResize(int newWidth, int newHeight)
544 CServiceBroker::GetWinSystem()->SetWindowResolution(newWidth, newHeight);
545 ApplyVideoResolution(RES_WINDOW);
546 CServiceBroker::GetWinSystem()->FinishWindowResize(newWidth, newHeight);
549 RESOLUTION CGraphicContext::GetVideoResolution() const
551 return m_Resolution;
554 void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res)
556 res.Overscan.left = 0;
557 res.Overscan.top = 0;
558 res.Overscan.right = res.iWidth;
559 res.Overscan.bottom = res.iHeight;
562 void CGraphicContext::ResetOverscan(RESOLUTION res, OVERSCAN &overscan)
564 overscan.left = 0;
565 overscan.top = 0;
567 RESOLUTION_INFO info = GetResInfo(res);
568 overscan.right = info.iWidth;
569 overscan.bottom = info.iHeight;
572 void CGraphicContext::ResetScreenParameters(RESOLUTION res)
574 RESOLUTION_INFO& info = CDisplaySettings::GetInstance().GetResolutionInfo(res);
576 info.iSubtitles = info.iHeight;
577 info.fPixelRatio = 1.0f;
578 info.iScreenWidth = info.iWidth;
579 info.iScreenHeight = info.iHeight;
580 ResetOverscan(res, info.Overscan);
583 void CGraphicContext::Clear()
585 CServiceBroker::GetRenderSystem()->InvalidateColorBuffer();
588 void CGraphicContext::Clear(UTILS::COLOR::Color color)
590 CServiceBroker::GetRenderSystem()->ClearBuffers(color);
593 void CGraphicContext::CaptureStateBlock()
595 CServiceBroker::GetRenderSystem()->CaptureStateBlock();
598 void CGraphicContext::ApplyStateBlock()
600 CServiceBroker::GetRenderSystem()->ApplyStateBlock();
603 const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
605 RESOLUTION_INFO info = CDisplaySettings::GetInstance().GetResolutionInfo(res);
607 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
609 if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
611 info.fPixelRatio /= 2;
612 info.iBlanking = 0;
613 info.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
615 info.iHeight = (info.iHeight - info.iBlanking) / 2;
616 info.Overscan.top /= 2;
617 info.Overscan.bottom = (info.Overscan.bottom - info.iBlanking) / 2;
618 info.iSubtitles = (info.iSubtitles - info.iBlanking) / 2;
621 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
623 if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
625 info.fPixelRatio *= 2;
626 info.iBlanking = 0;
627 info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
629 info.iWidth = (info.iWidth - info.iBlanking) / 2;
630 info.Overscan.left /= 2;
631 info.Overscan.right = (info.Overscan.right - info.iBlanking) / 2;
634 if (res == m_Resolution && m_fFPSOverride != 0)
636 info.fRefreshRate = m_fFPSOverride;
639 return info;
642 void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
644 RESOLUTION_INFO& curr = CDisplaySettings::GetInstance().GetResolutionInfo(res);
645 curr.Overscan = info.Overscan;
646 curr.iSubtitles = info.iSubtitles;
647 curr.fPixelRatio = info.fPixelRatio;
648 curr.guiInsets = info.guiInsets;
650 if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
652 curr.Overscan.right = info.Overscan.right * 2 + info.iBlanking;
653 if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
654 curr.fPixelRatio /= 2.0f;
657 if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
659 curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking;
660 curr.iSubtitles = info.iSubtitles * 2 + info.iBlanking;
661 if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
662 curr.fPixelRatio *= 2.0f;
666 const RESOLUTION_INFO CGraphicContext::GetResInfo() const
668 return GetResInfo(m_Resolution);
671 void CGraphicContext::GetGUIScaling(const RESOLUTION_INFO &res, float &scaleX, float &scaleY, TransformMatrix *matrix /* = NULL */)
673 if (m_Resolution != RES_INVALID)
675 // calculate necessary scalings
676 RESOLUTION_INFO info = GetResInfo();
677 float fFromWidth = (float)res.iWidth;
678 float fFromHeight = (float)res.iHeight;
679 auto fToPosX = info.Overscan.left + info.guiInsets.left;
680 auto fToPosY = info.Overscan.top + info.guiInsets.top;
681 auto fToWidth = info.Overscan.right - info.guiInsets.right - fToPosX;
682 auto fToHeight = info.Overscan.bottom - info.guiInsets.bottom - fToPosY;
684 float fZoom = (100 + CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_SKINZOOM)) * 0.01f;
686 fZoom -= 1.0f;
687 fToPosX -= fToWidth * fZoom * 0.5f;
688 fToWidth *= fZoom + 1.0f;
690 // adjust for aspect ratio as zoom is given in the vertical direction and we don't
691 // do aspect ratio corrections in the gui code
692 fZoom = fZoom / info.fPixelRatio;
693 fToPosY -= fToHeight * fZoom * 0.5f;
694 fToHeight *= fZoom + 1.0f;
696 scaleX = fFromWidth / fToWidth;
697 scaleY = fFromHeight / fToHeight;
698 if (matrix)
700 TransformMatrix guiScaler = TransformMatrix::CreateScaler(fToWidth / fFromWidth, fToHeight / fFromHeight, fToHeight / fFromHeight);
701 TransformMatrix guiOffset = TransformMatrix::CreateTranslation(fToPosX, fToPosY);
702 *matrix = guiOffset * guiScaler;
705 else
707 scaleX = scaleY = 1.0f;
708 if (matrix)
709 matrix->Reset();
713 void CGraphicContext::SetScalingResolution(const RESOLUTION_INFO &res, bool needsScaling)
715 m_windowResolution = res;
716 if (needsScaling && m_Resolution != RES_INVALID)
717 GetGUIScaling(res, m_guiTransform.scaleX, m_guiTransform.scaleY, &m_guiTransform.matrix);
718 else
720 m_guiTransform.Reset();
723 // reset our origin and camera
724 while (!m_origins.empty())
725 m_origins.pop();
726 m_origins.emplace(.0f, .0f);
727 while (!m_cameras.empty())
728 m_cameras.pop();
729 m_cameras.emplace(0.5f * m_iScreenWidth, 0.5f * m_iScreenHeight);
730 while (!m_stereoFactors.empty())
731 m_stereoFactors.pop();
732 m_stereoFactors.push(0.0f);
734 // and reset the final transform
735 m_finalTransform = m_guiTransform;
738 void CGraphicContext::SetRenderingResolution(const RESOLUTION_INFO &res, bool needsScaling)
740 std::unique_lock<CCriticalSection> lock(*this);
742 SetScalingResolution(res, needsScaling);
743 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
746 void CGraphicContext::SetStereoView(RENDER_STEREO_VIEW view)
748 m_stereoView = view;
750 while(!m_viewStack.empty())
751 m_viewStack.pop();
753 CRect viewport(0.0f, 0.0f, (float)m_iScreenWidth, (float)m_iScreenHeight);
755 m_viewStack.push(viewport);
757 viewport = StereoCorrection(viewport);
758 CServiceBroker::GetRenderSystem()->SetStereoMode(m_stereoMode, m_stereoView);
759 CServiceBroker::GetRenderSystem()->SetViewPort(viewport);
760 CServiceBroker::GetRenderSystem()->SetScissors(viewport);
763 void CGraphicContext::InvertFinalCoords(float &x, float &y) const
765 m_finalTransform.matrix.InverseTransformPosition(x, y);
768 float CGraphicContext::ScaleFinalXCoord(float x, float y) const
770 return m_finalTransform.matrix.TransformXCoord(x, y, 0);
773 float CGraphicContext::ScaleFinalYCoord(float x, float y) const
775 return m_finalTransform.matrix.TransformYCoord(x, y, 0);
778 float CGraphicContext::ScaleFinalZCoord(float x, float y) const
780 return m_finalTransform.matrix.TransformZCoord(x, y, 0);
783 void CGraphicContext::ScaleFinalCoords(float &x, float &y, float &z) const
785 m_finalTransform.matrix.TransformPosition(x, y, z);
788 float CGraphicContext::GetScalingPixelRatio() const
790 // assume the resolutions are different - we want to return the aspect ratio of the video resolution
791 // but only once it's been corrected for the skin -> screen coordinates scaling
792 return GetResInfo().fPixelRatio * (m_finalTransform.scaleY / m_finalTransform.scaleX);
795 void CGraphicContext::SetCameraPosition(const CPoint &camera)
797 // offset the camera from our current location (this is in XML coordinates) and scale it up to
798 // the screen resolution
799 CPoint cam(camera);
800 if (!m_origins.empty())
801 cam += m_origins.top();
803 cam.x *= (float)m_iScreenWidth / m_windowResolution.iWidth;
804 cam.y *= (float)m_iScreenHeight / m_windowResolution.iHeight;
806 m_cameras.push(cam);
807 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
810 void CGraphicContext::RestoreCameraPosition()
811 { // remove the top camera from the stack
812 assert(m_cameras.size());
813 m_cameras.pop();
814 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
817 void CGraphicContext::SetStereoFactor(float factor)
819 m_stereoFactors.push(factor);
820 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
823 void CGraphicContext::RestoreStereoFactor()
824 { // remove the top factor from the stack
825 assert(m_stereoFactors.size());
826 m_stereoFactors.pop();
827 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
830 float CGraphicContext::GetNormalizedDepth(uint32_t depth)
832 float normalizedDepth = static_cast<float>(depth);
833 normalizedDepth /= m_layer;
834 normalizedDepth = normalizedDepth * 2 - 1;
835 return normalizedDepth;
838 float CGraphicContext::GetTransformDepth(int32_t depthOffset)
840 float depth = static_cast<float>(m_finalTransform.matrix.depth + depthOffset);
841 depth /= m_layer;
842 depth = depth * 2 - 1;
843 return depth;
846 CRect CGraphicContext::GenerateAABB(const CRect &rect) const
848 // ------------------------
849 // |(x1, y1) (x2, y2)|
850 // | |
851 // |(x3, y3) (x4, y4)|
852 // ------------------------
854 float x1 = rect.x1, x2 = rect.x2, x3 = rect.x1, x4 = rect.x2;
855 float y1 = rect.y1, y2 = rect.y1, y3 = rect.y2, y4 = rect.y2;
857 float z = 0.0f;
858 ScaleFinalCoords(x1, y1, z);
859 CServiceBroker::GetRenderSystem()->Project(x1, y1, z);
861 z = 0.0f;
862 ScaleFinalCoords(x2, y2, z);
863 CServiceBroker::GetRenderSystem()->Project(x2, y2, z);
865 z = 0.0f;
866 ScaleFinalCoords(x3, y3, z);
867 CServiceBroker::GetRenderSystem()->Project(x3, y3, z);
869 z = 0.0f;
870 ScaleFinalCoords(x4, y4, z);
871 CServiceBroker::GetRenderSystem()->Project(x4, y4, z);
873 return CRect( std::min(std::min(std::min(x1, x2), x3), x4),
874 std::min(std::min(std::min(y1, y2), y3), y4),
875 std::max(std::max(std::max(x1, x2), x3), x4),
876 std::max(std::max(std::max(y1, y2), y3), y4));
879 // NOTE: This routine is currently called (twice) every time there is a <camera>
880 // tag in the skin. It actually only has to be called before we render
881 // something, so another option is to just save the camera coordinates
882 // and then have a routine called before every draw that checks whether
883 // the camera has changed, and if so, changes it. Similarly, it could set
884 // the world transform at that point as well (or even combine world + view
885 // to cut down on one setting)
886 void CGraphicContext::UpdateCameraPosition(const CPoint &camera, const float &factor)
888 float stereoFactor = 0.f;
889 if ( m_stereoMode != RENDER_STEREO_MODE_OFF
890 && m_stereoMode != RENDER_STEREO_MODE_MONO
891 && m_stereoView != RENDER_STEREO_VIEW_OFF)
893 RESOLUTION_INFO res = GetResInfo();
894 RESOLUTION_INFO desktop = GetResInfo(RES_DESKTOP);
895 float scaleRes = (static_cast<float>(res.iWidth) / static_cast<float>(desktop.iWidth));
896 float scaleX = static_cast<float>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_STEREOSTRENGTH)) * scaleRes;
897 stereoFactor = factor * (m_stereoView == RENDER_STEREO_VIEW_LEFT ? scaleX : -scaleX);
899 CServiceBroker::GetRenderSystem()->SetCameraPosition(camera, m_iScreenWidth, m_iScreenHeight, stereoFactor);
902 bool CGraphicContext::RectIsAngled(float x1, float y1, float x2, float y2) const
903 { // need only test 3 points, as they must be co-planer
904 if (m_finalTransform.matrix.TransformZCoord(x1, y1, 0)) return true;
905 if (m_finalTransform.matrix.TransformZCoord(x2, y2, 0)) return true;
906 if (m_finalTransform.matrix.TransformZCoord(x1, y2, 0)) return true;
907 return false;
910 const TransformMatrix &CGraphicContext::GetGUIMatrix() const
912 return m_finalTransform.matrix;
915 float CGraphicContext::GetGUIScaleX() const
917 return m_finalTransform.scaleX;
920 float CGraphicContext::GetGUIScaleY() const
922 return m_finalTransform.scaleY;
925 UTILS::COLOR::Color CGraphicContext::MergeAlpha(UTILS::COLOR::Color color) const
927 UTILS::COLOR::Color alpha = m_finalTransform.matrix.TransformAlpha((color >> 24) & 0xff);
928 if (alpha > 255) alpha = 255;
929 return ((alpha << 24) & 0xff000000) | (color & 0xffffff);
932 UTILS::COLOR::Color CGraphicContext::MergeColor(UTILS::COLOR::Color color) const
934 return m_finalTransform.matrix.TransformColor(color);
937 int CGraphicContext::GetWidth() const
939 return m_iScreenWidth;
942 int CGraphicContext::GetHeight() const
944 return m_iScreenHeight;
947 float CGraphicContext::GetFPS() const
949 if (m_Resolution != RES_INVALID)
951 RESOLUTION_INFO info = GetResInfo();
952 if (info.fRefreshRate > 0)
953 return info.fRefreshRate;
955 return 60.0f;
958 float CGraphicContext::GetDisplayLatency() const
960 float latency = CServiceBroker::GetWinSystem()->GetDisplayLatency();
961 if (latency < 0.0f)
963 // fallback
964 latency = (CServiceBroker::GetWinSystem()->NoOfBuffers() + 1) / GetFPS() * 1000.0f;
967 return latency;
970 bool CGraphicContext::IsFullScreenRoot () const
972 return m_bFullScreenRoot;
975 void CGraphicContext::ToggleFullScreen()
977 RESOLUTION uiRes;
979 if (m_bFullScreenRoot)
981 uiRes = RES_WINDOW;
983 else
985 if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP)
986 uiRes = CDisplaySettings::GetInstance().GetCurrentResolution();
987 else
988 uiRes = RES_DESKTOP;
991 CDisplaySettings::GetInstance().SetCurrentResolution(uiRes, true);
994 void CGraphicContext::SetMediaDir(const std::string &strMediaDir)
996 CServiceBroker::GetGUI()->GetTextureManager().SetTexturePath(strMediaDir);
997 m_strMediaDir = strMediaDir;
1000 const std::string& CGraphicContext::GetMediaDir() const
1002 return m_strMediaDir;
1006 void CGraphicContext::Flip(bool rendered, bool videoLayer)
1008 CServiceBroker::GetRenderSystem()->PresentRender(rendered, videoLayer);
1010 if(m_stereoMode != m_nextStereoMode)
1012 m_stereoMode = m_nextStereoMode;
1013 SetVideoResolution(GetVideoResolution(), true);
1014 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET);
1018 void CGraphicContext::GetAllowedResolutions(std::vector<RESOLUTION> &res)
1020 res.clear();
1022 res.push_back(RES_WINDOW);
1023 res.push_back(RES_DESKTOP);
1024 for (size_t r = (size_t) RES_CUSTOM; r < CDisplaySettings::GetInstance().ResolutionInfoSize(); r++)
1026 res.push_back((RESOLUTION) r);
1030 void CGraphicContext::SetRenderOrder(RENDER_ORDER renderOrder)
1032 m_renderOrder = renderOrder;
1033 if (renderOrder == RENDER_ORDER_ALL_BACK_TO_FRONT)
1034 CServiceBroker::GetRenderSystem()->SetDepthCulling(DEPTH_CULLING_OFF);
1035 else if (renderOrder == RENDER_ORDER_BACK_TO_FRONT)
1036 CServiceBroker::GetRenderSystem()->SetDepthCulling(DEPTH_CULLING_BACK_TO_FRONT);
1037 else if (renderOrder == RENDER_ORDER_FRONT_TO_BACK)
1038 CServiceBroker::GetRenderSystem()->SetDepthCulling(DEPTH_CULLING_FRONT_TO_BACK);
1041 uint32_t CGraphicContext::GetDepth(uint32_t addLayers)
1043 uint32_t layer = m_layer;
1044 m_layer += addLayers;
1045 return layer;
1048 void CGraphicContext::SetFPS(float fps)
1050 m_fFPSOverride = fps;