2 * Copyright (C) 2013-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.
9 #include "DisplaySettings.h"
11 #include "ServiceBroker.h"
12 #include "cores/VideoPlayer/VideoRenderers/ColorManager.h"
13 #include "dialogs/GUIDialogFileBrowser.h"
14 #include "guilib/GUIComponent.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "guilib/StereoscopicsManager.h"
17 #include "messaging/helpers/DialogHelper.h"
18 #include "rendering/RenderSystem.h"
19 #include "settings/AdvancedSettings.h"
20 #include "settings/Settings.h"
21 #include "settings/SettingsComponent.h"
22 #include "settings/lib/Setting.h"
23 #include "settings/lib/SettingDefinitions.h"
24 #include "storage/MediaManager.h"
25 #include "utils/StringUtils.h"
26 #include "utils/Variant.h"
27 #include "utils/XMLUtils.h"
28 #include "utils/log.h"
29 #include "windowing/GraphicContext.h"
30 #include "windowing/WinSystem.h"
41 #include "rendering/dx/DeviceResources.h"
44 using namespace KODI::MESSAGING
;
46 using KODI::MESSAGING::HELPERS::DialogResponse
;
48 // 0.1 second increments
49 #define MAX_REFRESH_CHANGE_DELAY 200
51 static RESOLUTION_INFO EmptyResolution
;
52 static RESOLUTION_INFO EmptyModifiableResolution
;
54 float square_error(float x
, float y
)
56 float yonx
= (x
> 0) ? y
/ x
: 0;
57 float xony
= (y
> 0) ? x
/ y
: 0;
58 return std::max(yonx
, xony
);
61 static std::string
ModeFlagsToString(unsigned int flags
, bool identifier
)
64 if(flags
& D3DPRESENTFLAG_INTERLACED
)
72 if(flags
& D3DPRESENTFLAG_MODE3DSBS
)
74 else if(flags
& D3DPRESENTFLAG_MODE3DTB
)
81 CDisplaySettings::CDisplaySettings()
83 m_resolutions
.resize(RES_CUSTOM
);
87 m_verticalShift
= 0.0f
;
88 m_nonLinearStretched
= false;
89 m_resolutionChangeAborted
= false;
92 CDisplaySettings::~CDisplaySettings() = default;
94 CDisplaySettings
& CDisplaySettings::GetInstance()
96 static CDisplaySettings sDisplaySettings
;
97 return sDisplaySettings
;
100 bool CDisplaySettings::Load(const TiXmlNode
*settings
)
102 std::unique_lock
<CCriticalSection
> lock(m_critical
);
103 m_calibrations
.clear();
105 if (settings
== NULL
)
108 const TiXmlElement
*pElement
= settings
->FirstChildElement("resolutions");
111 CLog::Log(LOGERROR
, "CDisplaySettings: settings file doesn't contain <resolutions>");
115 const TiXmlElement
*pResolution
= pElement
->FirstChildElement("resolution");
118 // get the data for this calibration
121 XMLUtils::GetString(pResolution
, "description", cal
.strMode
);
122 XMLUtils::GetInt(pResolution
, "subtitles", cal
.iSubtitles
);
123 XMLUtils::GetFloat(pResolution
, "pixelratio", cal
.fPixelRatio
);
125 XMLUtils::GetFloat(pResolution
, "refreshrate", cal
.fRefreshRate
);
126 XMLUtils::GetString(pResolution
, "output", cal
.strOutput
);
127 XMLUtils::GetString(pResolution
, "xrandrid", cal
.strId
);
130 const TiXmlElement
*pOverscan
= pResolution
->FirstChildElement("overscan");
133 XMLUtils::GetInt(pOverscan
, "left", cal
.Overscan
.left
);
134 XMLUtils::GetInt(pOverscan
, "top", cal
.Overscan
.top
);
135 XMLUtils::GetInt(pOverscan
, "right", cal
.Overscan
.right
);
136 XMLUtils::GetInt(pOverscan
, "bottom", cal
.Overscan
.bottom
);
139 // mark calibration as not updated
140 // we must not delete those, resolution just might not be available
141 cal
.iWidth
= cal
.iHeight
= 0;
143 // store calibration, avoid adding duplicates
145 for (ResolutionInfos::const_iterator it
= m_calibrations
.begin(); it
!= m_calibrations
.end(); ++it
)
147 if (StringUtils::EqualsNoCase(it
->strMode
, cal
.strMode
))
154 m_calibrations
.push_back(cal
);
157 pResolution
= pResolution
->NextSiblingElement("resolution");
164 bool CDisplaySettings::Save(TiXmlNode
*settings
) const
166 if (settings
== NULL
)
169 std::unique_lock
<CCriticalSection
> lock(m_critical
);
170 TiXmlElement
xmlRootElement("resolutions");
171 TiXmlNode
*pRoot
= settings
->InsertEndChild(xmlRootElement
);
176 for (ResolutionInfos::const_iterator it
= m_calibrations
.begin(); it
!= m_calibrations
.end(); ++it
)
178 // Write the resolution tag
179 TiXmlElement
resElement("resolution");
180 TiXmlNode
*pNode
= pRoot
->InsertEndChild(resElement
);
184 // Now write each of the pieces of information we need...
185 XMLUtils::SetString(pNode
, "description", it
->strMode
);
186 XMLUtils::SetInt(pNode
, "subtitles", it
->iSubtitles
);
187 XMLUtils::SetFloat(pNode
, "pixelratio", it
->fPixelRatio
);
189 XMLUtils::SetFloat(pNode
, "refreshrate", it
->fRefreshRate
);
190 XMLUtils::SetString(pNode
, "output", it
->strOutput
);
191 XMLUtils::SetString(pNode
, "xrandrid", it
->strId
);
194 // create the overscan child
195 TiXmlElement
overscanElement("overscan");
196 TiXmlNode
*pOverscanNode
= pNode
->InsertEndChild(overscanElement
);
197 if (pOverscanNode
== NULL
)
200 XMLUtils::SetInt(pOverscanNode
, "left", it
->Overscan
.left
);
201 XMLUtils::SetInt(pOverscanNode
, "top", it
->Overscan
.top
);
202 XMLUtils::SetInt(pOverscanNode
, "right", it
->Overscan
.right
);
203 XMLUtils::SetInt(pOverscanNode
, "bottom", it
->Overscan
.bottom
);
209 void CDisplaySettings::Clear()
211 std::unique_lock
<CCriticalSection
> lock(m_critical
);
212 m_calibrations
.clear();
213 m_resolutions
.clear();
214 m_resolutions
.resize(RES_CUSTOM
);
218 m_verticalShift
= 0.0f
;
219 m_nonLinearStretched
= false;
222 void CDisplaySettings::OnSettingAction(const std::shared_ptr
<const CSetting
>& setting
)
227 const std::string
&settingId
= setting
->GetId();
228 if (settingId
== "videoscreen.cms3dlut")
230 std::string path
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
232 CServiceBroker::GetMediaManager().GetLocalDrives(shares
);
233 if (CGUIDialogFileBrowser::ShowAndGetFile(shares
, ".3dlut", g_localizeStrings
.Get(36580), path
))
235 std::static_pointer_cast
<CSettingString
>(std::const_pointer_cast
<CSetting
>(setting
))->SetValue(path
);
238 else if (settingId
== "videoscreen.displayprofile")
240 std::string path
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
242 CServiceBroker::GetMediaManager().GetLocalDrives(shares
);
243 if (CGUIDialogFileBrowser::ShowAndGetFile(shares
, ".icc|.icm", g_localizeStrings
.Get(36581), path
))
245 std::static_pointer_cast
<CSettingString
>(std::const_pointer_cast
<CSetting
>(setting
))->SetValue(path
);
250 bool CDisplaySettings::OnSettingChanging(const std::shared_ptr
<const CSetting
>& setting
)
255 const std::string
&settingId
= setting
->GetId();
256 if (settingId
== CSettings::SETTING_VIDEOSCREEN_RESOLUTION
||
257 settingId
== CSettings::SETTING_VIDEOSCREEN_SCREEN
)
259 RESOLUTION newRes
= RES_DESKTOP
;
260 if (settingId
== CSettings::SETTING_VIDEOSCREEN_RESOLUTION
)
261 newRes
= (RESOLUTION
)std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
262 else if (settingId
== CSettings::SETTING_VIDEOSCREEN_SCREEN
)
264 int screen
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
266 // if triggered by a change of screenmode, screen may not have changed
267 if (screen
== GetCurrentDisplayMode())
270 // get desktop resolution for screen
271 newRes
= GetResolutionForScreen();
274 std::string screenmode
= GetStringFromResolution(newRes
);
275 if (!CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_VIDEOSCREEN_SCREENMODE
, screenmode
))
279 if (settingId
== CSettings::SETTING_VIDEOSCREEN_SCREENMODE
)
281 RESOLUTION oldRes
= GetCurrentResolution();
282 RESOLUTION newRes
= GetResolutionFromString(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
284 SetCurrentResolution(newRes
, false);
285 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(newRes
, false);
287 // check if the old or the new resolution was/is windowed
288 // in which case we don't show any prompt to the user
289 if (oldRes
!= RES_WINDOW
&& newRes
!= RES_WINDOW
&& oldRes
!= newRes
)
291 if (!m_resolutionChangeAborted
)
293 if (HELPERS::ShowYesNoDialogText(CVariant
{13110}, CVariant
{13111}, CVariant
{""},
294 CVariant
{""}, 15000) != DialogResponse::CHOICE_YES
)
296 m_resolutionChangeAborted
= true;
301 m_resolutionChangeAborted
= false;
304 else if (settingId
== CSettings::SETTING_VIDEOSCREEN_MONITOR
)
306 auto winSystem
= CServiceBroker::GetWinSystem();
307 if (winSystem
->SupportsScreenMove())
309 const std::string screen
=
310 std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
311 const unsigned int screenIdx
= winSystem
->GetScreenId(screen
);
312 winSystem
->MoveToScreen(screenIdx
);
314 winSystem
->UpdateResolutions();
315 RESOLUTION newRes
= GetResolutionForScreen();
317 SetCurrentResolution(newRes
, false);
318 winSystem
->GetGfxContext().SetVideoResolution(newRes
, true);
320 if (!m_resolutionChangeAborted
)
322 if (HELPERS::ShowYesNoDialogText(CVariant
{13110}, CVariant
{13111}, CVariant
{""}, CVariant
{""},
323 10000) != DialogResponse::CHOICE_YES
)
325 m_resolutionChangeAborted
= true;
330 m_resolutionChangeAborted
= false;
334 else if (settingId
== CSettings::SETTING_VIDEOSCREEN_10BITSURFACES
)
336 #ifdef TARGET_WINDOWS
337 DX::DeviceResources::Get()->ApplyDisplaySettings();
341 #if defined(HAVE_X11) || defined(TARGET_WINDOWS_DESKTOP) || defined(TARGET_DARWIN_OSX)
342 else if (settingId
== CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS
)
344 auto winSystem
= CServiceBroker::GetWinSystem();
345 #if defined(HAVE_X11)
346 winSystem
->UpdateResolutions();
347 #elif defined(TARGET_WINDOWS_DESKTOP) || defined(TARGET_DARWIN_OSX)
348 CGraphicContext
& gfxContext
= winSystem
->GetGfxContext();
349 gfxContext
.SetVideoResolution(gfxContext
.GetVideoResolution(), true);
357 bool CDisplaySettings::OnSettingUpdate(const std::shared_ptr
<CSetting
>& setting
,
358 const char* oldSettingId
,
359 const TiXmlNode
* oldSettingNode
)
364 const std::string
&settingId
= setting
->GetId();
365 if (settingId
== CSettings::SETTING_VIDEOSCREEN_SCREENMODE
)
367 std::shared_ptr
<CSettingString
> screenmodeSetting
= std::static_pointer_cast
<CSettingString
>(setting
);
368 std::string screenmode
= screenmodeSetting
->GetValue();
369 // in Eden there was no character ("i" or "p") indicating interlaced/progressive
370 // at the end so we just add a "p" and assume progressive
371 // no 3d mode existed before, so just assume std modes
372 if (screenmode
.size() == 20)
373 return screenmodeSetting
->SetValue(screenmode
+ "pstd");
374 if (screenmode
.size() == 21)
375 return screenmodeSetting
->SetValue(screenmode
+ "std");
377 else if (settingId
== CSettings::SETTING_VIDEOSCREEN_PREFEREDSTEREOSCOPICMODE
)
379 std::shared_ptr
<CSettingInt
> stereomodeSetting
= std::static_pointer_cast
<CSettingInt
>(setting
);
380 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
381 STEREOSCOPIC_PLAYBACK_MODE playbackMode
= (STEREOSCOPIC_PLAYBACK_MODE
) settings
->GetInt(CSettings::SETTING_VIDEOPLAYER_STEREOSCOPICPLAYBACKMODE
);
382 if (stereomodeSetting
->GetValue() == RENDER_STEREO_MODE_OFF
)
384 // if preferred playback mode was OFF, update playback mode to ignore
385 if (playbackMode
== STEREOSCOPIC_PLAYBACK_MODE_PREFERRED
)
386 settings
->SetInt(CSettings::SETTING_VIDEOPLAYER_STEREOSCOPICPLAYBACKMODE
, STEREOSCOPIC_PLAYBACK_MODE_IGNORE
);
387 return stereomodeSetting
->SetValue(RENDER_STEREO_MODE_AUTO
);
389 else if (stereomodeSetting
->GetValue() == RENDER_STEREO_MODE_MONO
)
391 // if preferred playback mode was MONO, update playback mode
392 if (playbackMode
== STEREOSCOPIC_PLAYBACK_MODE_PREFERRED
)
393 settings
->SetInt(CSettings::SETTING_VIDEOPLAYER_STEREOSCOPICPLAYBACKMODE
, STEREOSCOPIC_PLAYBACK_MODE_MONO
);
394 return stereomodeSetting
->SetValue(RENDER_STEREO_MODE_AUTO
);
401 void CDisplaySettings::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
406 const std::string
& settingId
= setting
->GetId();
407 if (settingId
== CSettings::SETTING_VIDEOSCREEN_WHITELIST
)
408 CResolutionUtils::PrintWhitelist();
411 void CDisplaySettings::SetMonitor(const std::string
& monitor
)
413 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
414 const std::string curMonitor
= settings
->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR
);
415 if (curMonitor
!= monitor
)
417 m_resolutionChangeAborted
= true;
418 settings
->SetString(CSettings::SETTING_VIDEOSCREEN_MONITOR
, monitor
);
422 void CDisplaySettings::SetCurrentResolution(RESOLUTION resolution
, bool save
/* = false */)
424 if (resolution
== RES_WINDOW
&& !CServiceBroker::GetWinSystem()->CanDoWindowed())
425 resolution
= RES_DESKTOP
;
429 // Save videoscreen.screenmode setting
430 std::string mode
= GetStringFromResolution(resolution
);
431 CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(
432 CSettings::SETTING_VIDEOSCREEN_SCREENMODE
, mode
);
434 // Check if videoscreen.screen setting also needs to be saved
435 // e.g. if ToggleFullscreen is called
436 int currentDisplayMode
= GetCurrentDisplayMode();
437 int currentDisplayModeSetting
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOSCREEN_SCREEN
);
438 if (currentDisplayMode
!= currentDisplayModeSetting
)
440 CServiceBroker::GetSettingsComponent()->GetSettings()->SetInt(CSettings::SETTING_VIDEOSCREEN_SCREEN
, currentDisplayMode
);
443 else if (resolution
!= m_currentResolution
)
445 m_currentResolution
= resolution
;
450 RESOLUTION
CDisplaySettings::GetDisplayResolution() const
452 return GetResolutionFromString(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_VIDEOSCREEN_SCREENMODE
));
455 const RESOLUTION_INFO
& CDisplaySettings::GetResolutionInfo(size_t index
) const
457 std::unique_lock
<CCriticalSection
> lock(m_critical
);
458 if (index
>= m_resolutions
.size())
459 return EmptyResolution
;
461 return m_resolutions
[index
];
464 const RESOLUTION_INFO
& CDisplaySettings::GetResolutionInfo(RESOLUTION resolution
) const
466 if (resolution
<= RES_INVALID
)
467 return EmptyResolution
;
469 return GetResolutionInfo((size_t)resolution
);
472 RESOLUTION_INFO
& CDisplaySettings::GetResolutionInfo(size_t index
)
474 std::unique_lock
<CCriticalSection
> lock(m_critical
);
475 if (index
>= m_resolutions
.size())
477 EmptyModifiableResolution
= RESOLUTION_INFO();
478 return EmptyModifiableResolution
;
481 return m_resolutions
[index
];
484 RESOLUTION_INFO
& CDisplaySettings::GetResolutionInfo(RESOLUTION resolution
)
486 if (resolution
<= RES_INVALID
)
488 EmptyModifiableResolution
= RESOLUTION_INFO();
489 return EmptyModifiableResolution
;
492 return GetResolutionInfo((size_t)resolution
);
495 void CDisplaySettings::AddResolutionInfo(const RESOLUTION_INFO
&resolution
)
497 std::unique_lock
<CCriticalSection
> lock(m_critical
);
498 RESOLUTION_INFO
res(resolution
);
500 if((res
.dwFlags
& D3DPRESENTFLAG_MODE3DTB
) == 0)
502 /* add corrections for some special case modes frame packing modes */
504 if(res
.iScreenWidth
== 1920
505 && res
.iScreenHeight
== 2205)
508 res
.dwFlags
|= D3DPRESENTFLAG_MODE3DTB
;
511 if(res
.iScreenWidth
== 1280
512 && res
.iScreenHeight
== 1470)
515 res
.dwFlags
|= D3DPRESENTFLAG_MODE3DTB
;
518 m_resolutions
.push_back(res
);
521 void CDisplaySettings::ApplyCalibrations()
523 std::unique_lock
<CCriticalSection
> lock(m_critical
);
524 // apply all calibrations to the resolutions
525 for (ResolutionInfos::const_iterator itCal
= m_calibrations
.begin(); itCal
!= m_calibrations
.end(); ++itCal
)
528 for (size_t res
= RES_DESKTOP
; res
< m_resolutions
.size(); ++res
)
530 if (StringUtils::EqualsNoCase(itCal
->strMode
, m_resolutions
[res
].strMode
))
533 m_resolutions
[res
].Overscan
.left
= itCal
->Overscan
.left
;
534 if (m_resolutions
[res
].Overscan
.left
< -m_resolutions
[res
].iWidth
/4)
535 m_resolutions
[res
].Overscan
.left
= -m_resolutions
[res
].iWidth
/4;
536 if (m_resolutions
[res
].Overscan
.left
> m_resolutions
[res
].iWidth
/4)
537 m_resolutions
[res
].Overscan
.left
= m_resolutions
[res
].iWidth
/4;
539 m_resolutions
[res
].Overscan
.top
= itCal
->Overscan
.top
;
540 if (m_resolutions
[res
].Overscan
.top
< -m_resolutions
[res
].iHeight
/4)
541 m_resolutions
[res
].Overscan
.top
= -m_resolutions
[res
].iHeight
/4;
542 if (m_resolutions
[res
].Overscan
.top
> m_resolutions
[res
].iHeight
/4)
543 m_resolutions
[res
].Overscan
.top
= m_resolutions
[res
].iHeight
/4;
545 m_resolutions
[res
].Overscan
.right
= itCal
->Overscan
.right
;
546 if (m_resolutions
[res
].Overscan
.right
< m_resolutions
[res
].iWidth
/ 2)
547 m_resolutions
[res
].Overscan
.right
= m_resolutions
[res
].iWidth
/ 2;
548 if (m_resolutions
[res
].Overscan
.right
> m_resolutions
[res
].iWidth
* 3/2)
549 m_resolutions
[res
].Overscan
.right
= m_resolutions
[res
].iWidth
*3/2;
551 m_resolutions
[res
].Overscan
.bottom
= itCal
->Overscan
.bottom
;
552 if (m_resolutions
[res
].Overscan
.bottom
< m_resolutions
[res
].iHeight
/ 2)
553 m_resolutions
[res
].Overscan
.bottom
= m_resolutions
[res
].iHeight
/ 2;
554 if (m_resolutions
[res
].Overscan
.bottom
> m_resolutions
[res
].iHeight
* 3/2)
555 m_resolutions
[res
].Overscan
.bottom
= m_resolutions
[res
].iHeight
* 3/2;
557 m_resolutions
[res
].iSubtitles
= itCal
->iSubtitles
;
558 if (m_resolutions
[res
].iSubtitles
< 0)
559 m_resolutions
[res
].iSubtitles
= 0;
560 if (m_resolutions
[res
].iSubtitles
> m_resolutions
[res
].iHeight
* 3 / 2)
561 m_resolutions
[res
].iSubtitles
= m_resolutions
[res
].iHeight
* 3 / 2;
563 m_resolutions
[res
].fPixelRatio
= itCal
->fPixelRatio
;
564 if (m_resolutions
[res
].fPixelRatio
< 0.5f
)
565 m_resolutions
[res
].fPixelRatio
= 0.5f
;
566 if (m_resolutions
[res
].fPixelRatio
> 2.0f
)
567 m_resolutions
[res
].fPixelRatio
= 2.0f
;
574 void CDisplaySettings::UpdateCalibrations()
576 std::unique_lock
<CCriticalSection
> lock(m_critical
);
578 if (m_resolutions
.size() <= RES_DESKTOP
)
581 // Add new (unique) resolutions
582 for (ResolutionInfos::const_iterator
res(m_resolutions
.cbegin() + RES_CUSTOM
); res
!= m_resolutions
.cend(); ++res
)
583 if (std::find_if(m_calibrations
.cbegin(), m_calibrations
.cend(),
584 [&](const RESOLUTION_INFO
& info
) { return StringUtils::EqualsNoCase(res
->strMode
, info
.strMode
); }) == m_calibrations
.cend())
585 m_calibrations
.push_back(*res
);
587 for (auto &cal
: m_calibrations
)
589 ResolutionInfos::const_iterator
res(std::find_if(m_resolutions
.cbegin() + RES_DESKTOP
, m_resolutions
.cend(),
590 [&](const RESOLUTION_INFO
& info
) { return StringUtils::EqualsNoCase(cal
.strMode
, info
.strMode
); }));
592 if (res
!= m_resolutions
.cend())
594 //! @todo erase calibrations with default values
600 void CDisplaySettings::ClearCalibrations()
602 std::unique_lock
<CCriticalSection
> lock(m_critical
);
603 m_calibrations
.clear();
606 DisplayMode
CDisplaySettings::GetCurrentDisplayMode() const
608 if (GetCurrentResolution() == RES_WINDOW
)
611 return DM_FULLSCREEN
;
614 RESOLUTION
CDisplaySettings::FindBestMatchingResolution(const std::map
<RESOLUTION
, RESOLUTION_INFO
> &resolutionInfos
, int width
, int height
, float refreshrate
, unsigned flags
)
616 // find the closest match to these in our res vector. If we have the screen, we score the res
617 RESOLUTION bestRes
= RES_DESKTOP
;
618 float bestScore
= FLT_MAX
;
619 flags
&= D3DPRESENTFLAG_MODEMASK
;
621 for (std::map
<RESOLUTION
, RESOLUTION_INFO
>::const_iterator it
= resolutionInfos
.begin(); it
!= resolutionInfos
.end(); ++it
)
623 const RESOLUTION_INFO
&info
= it
->second
;
625 if ((info
.dwFlags
& D3DPRESENTFLAG_MODEMASK
) != flags
)
628 float score
= 10 * (square_error((float)info
.iScreenWidth
, (float)width
) +
629 square_error((float)info
.iScreenHeight
, (float)height
) +
630 square_error(info
.fRefreshRate
, refreshrate
));
631 if (score
< bestScore
)
641 RESOLUTION
CDisplaySettings::GetResolutionFromString(const std::string
&strResolution
)
644 if (strResolution
== "DESKTOP")
646 else if (strResolution
== "WINDOW")
648 else if (strResolution
.size() >= 20)
650 // format: WWWWWHHHHHRRR.RRRRRP333, where W = width, H = height, R = refresh, P = interlace, 3 = stereo mode
651 int width
= std::strtol(StringUtils::Mid(strResolution
, 0,5).c_str(), NULL
, 10);
652 int height
= std::strtol(StringUtils::Mid(strResolution
, 5,5).c_str(), NULL
, 10);
653 float refresh
= (float)std::strtod(StringUtils::Mid(strResolution
, 10,9).c_str(), NULL
);
656 // look for 'i' and treat everything else as progressive,
657 if(StringUtils::Mid(strResolution
, 19,1) == "i")
658 flags
|= D3DPRESENTFLAG_INTERLACED
;
660 if(StringUtils::Mid(strResolution
, 20,3) == "sbs")
661 flags
|= D3DPRESENTFLAG_MODE3DSBS
;
662 else if(StringUtils::Mid(strResolution
, 20,3) == "tab")
663 flags
|= D3DPRESENTFLAG_MODE3DTB
;
665 std::map
<RESOLUTION
, RESOLUTION_INFO
> resolutionInfos
;
666 for (size_t resolution
= RES_DESKTOP
; resolution
< CDisplaySettings::GetInstance().ResolutionInfoSize(); resolution
++)
667 resolutionInfos
.insert(std::make_pair((RESOLUTION
)resolution
, CDisplaySettings::GetInstance().GetResolutionInfo(resolution
)));
669 return FindBestMatchingResolution(resolutionInfos
, width
, height
, refresh
, flags
);
675 std::string
CDisplaySettings::GetStringFromResolution(RESOLUTION resolution
, float refreshrate
/* = 0.0f */)
677 if (resolution
== RES_WINDOW
)
680 if (resolution
>= RES_DESKTOP
&& resolution
< (RESOLUTION
)CDisplaySettings::GetInstance().ResolutionInfoSize())
682 const RESOLUTION_INFO
&info
= CDisplaySettings::GetInstance().GetResolutionInfo(resolution
);
683 // also handle RES_DESKTOP resolutions with non-default refresh rates
684 if (resolution
!= RES_DESKTOP
|| (refreshrate
> 0.0f
&& refreshrate
!= info
.fRefreshRate
))
686 return StringUtils::Format("{:05}{:05}{:09.5f}{}", info
.iScreenWidth
, info
.iScreenHeight
,
687 refreshrate
> 0.0f
? refreshrate
: info
.fRefreshRate
,
688 ModeFlagsToString(info
.dwFlags
, true));
695 RESOLUTION
CDisplaySettings::GetResolutionForScreen()
697 DisplayMode mode
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOSCREEN_SCREEN
);
698 if (mode
== DM_WINDOWED
)
704 static inline bool ModeSort(const StringSettingOption
& i
, const StringSettingOption
& j
)
706 return (i
.value
> j
.value
);
709 void CDisplaySettings::SettingOptionsModesFiller(const std::shared_ptr
<const CSetting
>& setting
,
710 std::vector
<StringSettingOption
>& list
,
711 std::string
& current
,
714 for (auto index
= (unsigned int)RES_CUSTOM
; index
< CDisplaySettings::GetInstance().ResolutionInfoSize(); ++index
)
716 const auto mode
= CDisplaySettings::GetInstance().GetResolutionInfo(index
);
718 if (mode
.dwFlags
^ D3DPRESENTFLAG_INTERLACED
)
720 auto setting
= GetStringFromResolution((RESOLUTION
)index
, mode
.fRefreshRate
);
723 StringUtils::Format("{}x{}{} {:0.2f}Hz", mode
.iScreenWidth
, mode
.iScreenHeight
,
724 ModeFlagsToString(mode
.dwFlags
, false), mode
.fRefreshRate
),
729 std::sort(list
.begin(), list
.end(), ModeSort
);
732 void CDisplaySettings::SettingOptionsRefreshChangeDelaysFiller(
733 const SettingConstPtr
& setting
,
734 std::vector
<IntegerSettingOption
>& list
,
738 list
.emplace_back(g_localizeStrings
.Get(13551), 0);
740 for (int i
= 1; i
<= MAX_REFRESH_CHANGE_DELAY
; i
++)
742 StringUtils::Format(g_localizeStrings
.Get(13553), static_cast<double>(i
) / 10.0), i
);
745 void CDisplaySettings::SettingOptionsRefreshRatesFiller(const SettingConstPtr
& setting
,
746 std::vector
<StringSettingOption
>& list
,
747 std::string
& current
,
750 // get the proper resolution
751 RESOLUTION res
= CDisplaySettings::GetInstance().GetDisplayResolution();
752 if (res
< RES_WINDOW
)
755 // only add "Windowed" if in windowed mode
756 if (res
== RES_WINDOW
)
759 list
.emplace_back(g_localizeStrings
.Get(242), current
);
763 RESOLUTION_INFO resInfo
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
764 // The only meaningful parts of res here are iScreenWidth, iScreenHeight
765 std::vector
<REFRESHRATE
> refreshrates
= CServiceBroker::GetWinSystem()->RefreshRates(resInfo
.iScreenWidth
, resInfo
.iScreenHeight
, resInfo
.dwFlags
);
768 for (std::vector
<REFRESHRATE
>::const_iterator refreshrate
= refreshrates
.begin(); refreshrate
!= refreshrates
.end(); ++refreshrate
)
770 std::string screenmode
= GetStringFromResolution((RESOLUTION
)refreshrate
->ResInfo_Index
, refreshrate
->RefreshRate
);
771 if (!match
&& StringUtils::EqualsNoCase(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue(), screenmode
))
773 list
.emplace_back(StringUtils::Format("{:.2f}", refreshrate
->RefreshRate
), screenmode
);
777 current
= GetStringFromResolution(res
, CServiceBroker::GetWinSystem()->DefaultRefreshRate(refreshrates
).RefreshRate
);
780 void CDisplaySettings::SettingOptionsResolutionsFiller(const SettingConstPtr
& setting
,
781 std::vector
<IntegerSettingOption
>& list
,
785 RESOLUTION res
= CDisplaySettings::GetInstance().GetDisplayResolution();
786 RESOLUTION_INFO info
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
787 if (res
== RES_WINDOW
)
790 list
.emplace_back(g_localizeStrings
.Get(242), res
);
794 std::map
<RESOLUTION
, RESOLUTION_INFO
> resolutionInfos
;
795 std::vector
<RESOLUTION_WHR
> resolutions
= CServiceBroker::GetWinSystem()->ScreenResolutions(info
.fRefreshRate
);
796 for (std::vector
<RESOLUTION_WHR
>::const_iterator resolution
= resolutions
.begin(); resolution
!= resolutions
.end(); ++resolution
)
798 const std::string resLabel
=
799 StringUtils::Format("{}x{}{}{}", resolution
->m_screenWidth
, resolution
->m_screenHeight
,
800 ModeFlagsToString(resolution
->flags
, false),
801 resolution
->width
> resolution
->m_screenWidth
&&
802 resolution
->height
> resolution
->m_screenHeight
805 list
.emplace_back(resLabel
, resolution
->ResInfo_Index
);
807 resolutionInfos
.insert(std::make_pair((RESOLUTION
)resolution
->ResInfo_Index
, CDisplaySettings::GetInstance().GetResolutionInfo(resolution
->ResInfo_Index
)));
810 // ids are unique, so try to find a match by id first. Then resort to best matching resolution.
811 if (!info
.strId
.empty())
813 const auto it
= std::find_if(resolutionInfos
.begin(), resolutionInfos
.end(),
814 [&](const std::pair
<RESOLUTION
, RESOLUTION_INFO
>& resItem
) {
815 return info
.strId
== resItem
.second
.strId
;
818 it
!= resolutionInfos
.end()
820 : FindBestMatchingResolution(resolutionInfos
, info
.iScreenWidth
, info
.iScreenHeight
,
821 info
.fRefreshRate
, info
.dwFlags
);
825 current
= FindBestMatchingResolution(resolutionInfos
, info
.iScreenWidth
, info
.iScreenHeight
,
826 info
.fRefreshRate
, info
.dwFlags
);
831 void CDisplaySettings::SettingOptionsDispModeFiller(const SettingConstPtr
& setting
,
832 std::vector
<IntegerSettingOption
>& list
,
836 // The user should only be able to disable windowed modes with the canwindowed
837 // setting. When the user sets canwindowed to true but the windowing system
838 // does not support windowed modes, we would just shoot ourselves in the foot
839 // by offering the option.
840 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_canWindowed
&& CServiceBroker::GetWinSystem()->CanDoWindowed())
841 list
.emplace_back(g_localizeStrings
.Get(242), DM_WINDOWED
);
843 list
.emplace_back(g_localizeStrings
.Get(244), DM_FULLSCREEN
);
846 void CDisplaySettings::SettingOptionsStereoscopicModesFiller(
847 const SettingConstPtr
& setting
,
848 std::vector
<IntegerSettingOption
>& list
,
852 CGUIComponent
*gui
= CServiceBroker::GetGUI();
855 const CStereoscopicsManager
&stereoscopicsManager
= gui
->GetStereoscopicsManager();
857 for (int i
= RENDER_STEREO_MODE_OFF
; i
< RENDER_STEREO_MODE_COUNT
; i
++)
859 RENDER_STEREO_MODE mode
= (RENDER_STEREO_MODE
) i
;
860 if (CServiceBroker::GetRenderSystem()->SupportsStereo(mode
))
861 list
.emplace_back(stereoscopicsManager
.GetLabelForStereoMode(mode
), mode
);
866 void CDisplaySettings::SettingOptionsPreferredStereoscopicViewModesFiller(
867 const SettingConstPtr
& setting
,
868 std::vector
<IntegerSettingOption
>& list
,
872 const CStereoscopicsManager
&stereoscopicsManager
= CServiceBroker::GetGUI()->GetStereoscopicsManager();
874 list
.emplace_back(stereoscopicsManager
.GetLabelForStereoMode(RENDER_STEREO_MODE_AUTO
),
875 RENDER_STEREO_MODE_AUTO
); // option for autodetect
876 // don't add "off" to the list of preferred modes as this doesn't make sense
877 for (int i
= RENDER_STEREO_MODE_OFF
+1; i
< RENDER_STEREO_MODE_COUNT
; i
++)
879 RENDER_STEREO_MODE mode
= (RENDER_STEREO_MODE
) i
;
880 // also skip "mono" mode which is no real stereoscopic mode
881 if (mode
!= RENDER_STEREO_MODE_MONO
&& CServiceBroker::GetRenderSystem()->SupportsStereo(mode
))
882 list
.emplace_back(stereoscopicsManager
.GetLabelForStereoMode(mode
), mode
);
886 void CDisplaySettings::SettingOptionsMonitorsFiller(const SettingConstPtr
& setting
,
887 std::vector
<StringSettingOption
>& list
,
888 std::string
& current
,
891 auto winSystem
= CServiceBroker::GetWinSystem();
895 auto settingsComponent
= CServiceBroker::GetSettingsComponent();
896 if (!settingsComponent
)
899 auto settings
= settingsComponent
->GetSettings();
903 const std::vector
<std::string
> monitors
= winSystem
->GetConnectedOutputs();
904 std::string currentMonitor
= settings
->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR
);
906 bool foundMonitor
= false;
907 for (auto const& monitor
: monitors
)
909 if(monitor
== currentMonitor
)
913 list
.emplace_back(monitor
, monitor
);
916 if (!foundMonitor
&& !current
.empty())
918 // Add current value so no monitor change is triggered when entering the settings screen and
919 // the preferred monitor is preserved
920 list
.emplace_back(current
, current
);
924 void CDisplaySettings::ClearCustomResolutions()
926 if (m_resolutions
.size() > RES_CUSTOM
)
928 std::vector
<RESOLUTION_INFO
>::iterator firstCustom
= m_resolutions
.begin()+RES_CUSTOM
;
929 m_resolutions
.erase(firstCustom
, m_resolutions
.end());
933 void CDisplaySettings::SettingOptionsCmsModesFiller(const SettingConstPtr
& setting
,
934 std::vector
<IntegerSettingOption
>& list
,
938 list
.emplace_back(g_localizeStrings
.Get(36580), CMS_MODE_3DLUT
);
940 list
.emplace_back(g_localizeStrings
.Get(36581), CMS_MODE_PROFILE
);
944 void CDisplaySettings::SettingOptionsCmsWhitepointsFiller(const SettingConstPtr
& setting
,
945 std::vector
<IntegerSettingOption
>& list
,
949 list
.emplace_back(g_localizeStrings
.Get(36586), CMS_WHITEPOINT_D65
);
950 list
.emplace_back(g_localizeStrings
.Get(36587), CMS_WHITEPOINT_D93
);
953 void CDisplaySettings::SettingOptionsCmsPrimariesFiller(const SettingConstPtr
& setting
,
954 std::vector
<IntegerSettingOption
>& list
,
958 list
.emplace_back(g_localizeStrings
.Get(36588), CMS_PRIMARIES_AUTO
);
959 list
.emplace_back(g_localizeStrings
.Get(36589), CMS_PRIMARIES_BT709
);
960 list
.emplace_back(g_localizeStrings
.Get(36579), CMS_PRIMARIES_BT2020
);
961 list
.emplace_back(g_localizeStrings
.Get(36590), CMS_PRIMARIES_170M
);
962 list
.emplace_back(g_localizeStrings
.Get(36591), CMS_PRIMARIES_BT470M
);
963 list
.emplace_back(g_localizeStrings
.Get(36592), CMS_PRIMARIES_BT470BG
);
964 list
.emplace_back(g_localizeStrings
.Get(36593), CMS_PRIMARIES_240M
);
967 void CDisplaySettings::SettingOptionsCmsGammaModesFiller(const SettingConstPtr
& setting
,
968 std::vector
<IntegerSettingOption
>& list
,
972 list
.emplace_back(g_localizeStrings
.Get(36582), CMS_TRC_BT1886
);
973 list
.emplace_back(g_localizeStrings
.Get(36583), CMS_TRC_INPUT_OFFSET
);
974 list
.emplace_back(g_localizeStrings
.Get(36584), CMS_TRC_OUTPUT_OFFSET
);
975 list
.emplace_back(g_localizeStrings
.Get(36585), CMS_TRC_ABSOLUTE
);