8#include <QElapsedTimer>
14#include <QQuickWindow>
29#if CONFIG_WAYLANDEXTRAS
53#define LOC QString("Display: ")
99#if CONFIG_WAYLANDEXTRAS
145 bool spanall =
false;
150 result.append(tr(
"Spanning %1 screens").arg(screencount));
151 result.append(tr(
"Total bounds") + QString(
"\t: %1x%2")
160 result.append(tr(
"Supported HDR formats\t: %1").arg(hdr.join(
",")));
162 result.append(tr(
"HDR mode switching is not available"));
163 if (
auto brightness =
m_hdrState->GetMaxLuminance(); brightness > 1.0)
164 result.append(tr(
"Max display brightness\t: %1 nits").arg(
static_cast<int>(brightness)));
169 result.append(tr(
"Variable refresh rate '%1': %2 %3")
171 m_vrrState->Enabled() ? tr(
"Enabled") : tr(
"Disabled"),
176 const auto screens = QGuiApplication::screens();
178 for (
auto *screen : std::as_const(screens))
183 auto id = QString(
"(%1)").arg(screen->manufacturer());
184 if (screen ==
current && !spanall)
185 result.append(tr(
"Current screen\t: %1 %2").arg(screen->name(),
id));
187 result.append(tr(
"Screen\t\t: %1 %2").arg(screen->name(),
id));
188 result.append(tr(
"Size") + QString(
"\t\t: %1mmx%2mm")
189 .arg(screen->physicalSize().width()).arg(screen->physicalSize().height()));
194 result.append(tr(
"Aspect ratio") + QString(
"\t: %1 (%2)")
195 .arg(aspect, 0,
'f', 3).arg(source));
198 result.append(tr(
"Current mode") + QString(
"\t: %1x%2@%3Hz")
204 result.append(tr(
"Available modes:"));
205 for (
auto it = modes.crbegin(); it != modes.crend(); ++it)
206 result.append(
" " + it->ToString());
216 : m_screen(GetDesiredScreen())
225 auto *guiapp = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
226 if (guiapp ==
nullptr)
236 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Deleting");
266 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Have main widget");
270 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Have main window");
296 return QGuiApplication::screens().size();
341 QScreen* newscreen =
nullptr;
351 bool windowed =
GetMythDB()->GetBoolSetting(
"RunFrontendInWindow",
false) &&
357 QPoint point = windowed ?
override.topLeft() :
override.bottomRight();
358 QList screens = QGuiApplication::screens();
359 for (QScreen *screen : std::as_const(screens))
361 if (screen->geometry().contains(point))
364 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
365 "Geometry override places window in screen '%1'").arg(newscreen->name()));
374 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Using primary screen for multiscreen");
375 newscreen = QGuiApplication::primaryScreen();
382 QList screens = QGuiApplication::screens();
383 for (QScreen *screen : std::as_const(screens))
385 if (!name.isEmpty() && name == screen->name())
387 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found screen '%1'").arg(name));
397 int screen_num = name.toInt(&ok);
398 QList<QScreen *>screens = QGuiApplication::screens();
399 if (ok && (screen_num >= 0) && (screen_num < screens.size()))
401 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found screen number %1 (%2)")
402 .arg(name, screens[screen_num]->name()));
403 newscreen = screens[screen_num];
410 QScreen *primary = QGuiApplication::primaryScreen();
411 if (name.isEmpty() && primary)
413 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Defaulting to primary screen (%1)")
414 .arg(primary->name()));
416 else if (name !=
"-1" && primary)
418 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen '%1' not found, defaulting to primary screen (%2)")
419 .arg(name, primary->name()));
434 disconnect(
m_screen,
nullptr,
this,
nullptr);
445 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Qt screen pixel ratio changed to %1")
446 .arg(DPI, 2,
'f', 2,
'0'));
463 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen '%1' removed").arg(qScreen->name()));
469 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"New screen geometry: %1x%2+%3+%4")
470 .arg(Geo.width()).arg(Geo.height()).arg(Geo.left()).arg(Geo.top()));
496 m_physicalSize = QSize(
static_cast<int>(screen->physicalSize().width()),
497 static_cast<int>(screen->physicalSize().height()));
508 QString mfg = qScreen->manufacturer();
511 QString model = qScreen->model();
514 return QString(
"(Make: %1 Model: %2)").arg(mfg, model);
522 auto geom = qScreen->geometry();
523 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 screen '%2' %3")
525 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Qt screen pixel ratio: %1")
526 .arg(qScreen->devicePixelRatio(), 2,
'f', 2,
'0'));
527 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Geometry: %1x%2+%3+%4 Size(Qt): %5mmx%6mm")
528 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
529 .arg(qScreen->physicalSize().width()).arg(qScreen->physicalSize().height()));
531 if (qScreen->virtualGeometry() != geom)
533 geom = qScreen->virtualGeometry();
534 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Total virtual geometry: %1x%2+%3+%4")
535 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top()));
556 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Desktop video mode: %1x%2 %3Hz")
561 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Display is using sRGB colourspace");
563 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Display has custom colourspace");
575 double aspectratio = 0.0;
576 GetMythDB()->GetResolutionSetting(
"GuiVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
577 GetMythDB()->GetResolutionSetting(
"DisplaySize", mmwidth, mmheight);
581 pixelwidth = pixelheight = 0;
582 GetMythDB()->GetResolutionSetting(
"TVVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
586 for (
int i = 0;
true; ++i)
592 double iaspect = 0.0;
593 double oaspect = 0.0;
597 GetMythDB()->GetResolutionSetting(
"VidMode", iw, ih, iaspect, irate, i);
598 GetMythDB()->GetResolutionSetting(
"TVVidMode", ow, oh, oaspect, orate, i);
600 if ((!iw && !ih && qFuzzyIsNull(irate)) || !(ih && ow && oh))
604 MythDisplayMode scr(QSize(ow, oh), QSize(mmwidth, mmheight), oaspect, orate);
619 const auto screens = QGuiApplication::screens();
620 for (
auto * screen : std::as_const(screens))
622 auto dim = screen->geometry();
624 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Screen %1: %2x%3 %4")
625 .arg(screen->name()).arg(dim.width()).arg(dim.height()).arg(extra));
628 const auto * primary = QGuiApplication::primaryScreen();
631 if (!screens.empty())
632 primary = screens.front();
635 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Qt has no screens!");
640 LOG(VB_GUI, LOG_INFO,
LOC +QString(
"Primary screen: %1.").arg(primary->name()));
643 auto dim = primary->virtualSize();
644 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Total desktop dim: %1x%2, over %3 screen[s].")
645 .arg(dim.width()).arg(dim.height()).arg(numScreens));
649 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Using entire desktop."));
654 if (!
GetMythDB()->GetBoolSetting(
"ForceFullScreen",
false) &&
655 GetMythDB()->GetBoolSetting(
"RunFrontendInWindow",
false))
657 LOG(VB_GUI, LOG_INFO,
LOC +
"Running in a window");
667 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Using screen %1: %2x%3 at %4+%5")
705 double targetrate = 0.0;
706 double aspectoverride = 0.0;
710 Size.width(), Size.height(), Rate);
717 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Found custom screen override %1x%2 Aspect %3")
718 .arg(next.
Width()).arg(next.
Height()).arg(aspectoverride));
724 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to match best refresh rate %1Hz")
725 .arg(Rate, 0,
'f', 3));
740 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Ignoring mode switch to %1Hz - VRR enabled")
741 .arg(Rate, 0,
'f', 3));
744 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Allowing mode switch with VRR enabled for new resolution");
750 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using current mode %1x%2@%3Hz")
755 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Trying mode %1x%2@%3Hz")
760 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to change mode to %1x%2@%3Hz")
771 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switched to %1x%2@%3Hz for video %4x%5")
773 .arg(
m_refreshRate, 0,
'f', 3).arg(Size.width()).arg(Size.height()));
789 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using %1x%2@%3Hz for GUI")
796 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to change mode to %1x%2@%3Hz")
806 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switched to %1x%2@%3Hz")
827 auto max = std::get<1>(range) > 60 ? std::get<1>(range) : 60;
840 auto targetrate =
static_cast<double>(NAN);
846 return modes[
static_cast<size_t>(match)].RefreshRates();
879 auto valid = [](
double Aspect) {
return (Aspect > 0.1 && Aspect < 10.0); };
885 Source = tr(
"Video mode override");
908 Source = tr(
"Multiscreen estimate");
919 if (valid(calculated))
921 if ((
override < 0.0) || !valid(detected))
923 Source = tr(
"Square pixels");
956 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Supported HDR formats: %1")
958 if (
auto brightness =
m_hdrState->GetMaxLuminance(); brightness > 1.0)
960 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Display reports max brightness of %1 nits")
961 .arg(
static_cast<int>(brightness)));
977 auto sortscreens = [](
const QScreen* First,
const QScreen* Second)
979 if (First->geometry().left() < Second->geometry().left())
981 if (First->geometry().top() < Second->geometry().top())
987 double result = 16.0 / 9.0;
989 QList<QScreen*> screens;
991 screens =
m_screen->virtualSiblings();
996 std::sort(screens.begin(), screens.end(), sortscreens);
997 QList<double> aspectratios;
998 QSize totalresolution;
1003 for (
auto it = screens.constBegin() ; it != screens.constEnd(); ++it)
1005 QRect geom = (*it)->geometry();
1006 totalresolution += geom.size();
1007 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"%1x%2+%3+%4 %5")
1008 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
1009 .arg((*it)->physicalSize().width() / (*it)->physicalSize().height()));
1010 if (lastleft < geom.left())
1013 lastleft = geom.left();
1015 if (lasttop < geom.top())
1018 lasttop = geom.top();
1021 aspectratios << (*it)->physicalSize().width() / (*it)->physicalSize().height();
1026 if (!totalresolution.isEmpty())
1027 result =
static_cast<double>(totalresolution.width()) / totalresolution.height();
1029 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen layout: %1x%2").arg(rows).arg(columns));
1030 if (rows == columns)
1032 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Grid layout");
1034 else if (rows == 1 && columns > 1)
1036 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Horizontal layout");
1038 else if (columns == 1 && rows > 1)
1040 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Vertical layout");
1044 LOG(VB_GENERAL, LOG_INFO,
1045 LOC + QString(
"Unsupported layout - defaulting to %1 (%2/%3)")
1046 .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1051 double aspectratio = 0.0;
1052 double average = 0.0;
1054 for (
auto it2 = aspectratios.constBegin() ; it2 != aspectratios.constEnd(); ++it2, ++count)
1056 aspectratio += *it2;
1057 average = aspectratio / count;
1058 if (qAbs(*it2 - average) > 0.1)
1060 LOG(VB_GENERAL, LOG_INFO,
LOC +
1061 QString(
"Inconsistent aspect ratios - defaulting to %1 (%2/%3)")
1062 .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1067 aspectratio = (average * columns) / rows;
1068 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Estimated aspect ratio: %1")
1090 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Waiting for resolution change");
1093 timer.setSingleShot(
true);
1094 connect(&timer, &
QTimer::timeout, [](){
LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Timed out wating for screen change"); });
1110 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Waiting for new screen");
1113 timer.setSingleShot(
true);
1114 connect(&timer, &
QTimer::timeout, [](){
LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Timed out waiting for new screen"); });
1125 if (pauselengthinms)
1127 LOG(VB_GENERAL, LOG_INFO,
LOC +
1128 QString(
"Pausing %1ms for video mode switch").arg(pauselengthinms));
1131 timer.setSingleShot(
true);
1134 timer.start(pauselengthinms);
1144 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Available modes:");
1147 auto rates = (*it).RefreshRates();
1148 QStringList rateslist;
1149 for (
auto it2 = rates.crbegin(); it2 != rates.crend(); ++it2)
1150 rateslist.append(QString(
"%1").arg(*it2, 2,
'f', 2,
'0'));
1151 if (rateslist.empty())
1152 rateslist.append(
"Variable rate?");
1153 LOG(VB_PLAYBACK, LOG_INFO, QString(
"%1x%2\t%3")
1154 .arg((*it).Width()).arg((*it).Height()).arg(rateslist.join(
"\t")));
1166 auto forcevrr = CmdLine.
toBool(
"vrr");
1167 bool gsyncchanged =
false;
1168 bool freesyncchanged =
false;
1170#if CONFIG_QTWEBENGINE
1171 QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
1172 QQuickWindow::setSceneGraphBackend(
"software");
1173 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Using shared OpenGL Contexts");
1177 QSurfaceFormat format;
1180 if (qEnvironmentVariableIsSet(
"MYTHTV_DEPTH"))
1183 int depth =
std::clamp(qEnvironmentVariableIntValue(
"MYTHTV_DEPTH"), 6, 16);
1184 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Trying to force depth to '%1'").arg(depth));
1185 format.setRedBufferSize(depth);
1189 format.setDepthBufferSize(0);
1190 format.setStencilBufferSize(0);
1192 format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
1193 format.setProfile(QSurfaceFormat::CompatibilityProfile);
1194 format.setSwapInterval(SwapInterval);
1195 QSurfaceFormat::setDefaultFormat(format);
1200 QApplication::setDesktopSettingsAware(
false);
1203#if CONFIG_DRM && CONFIG_QTPRIVATEHEADERS
1209#if CONFIG_WAYLANDEXTRAS
1214 MythDRMDevice::SetupDRM(CmdLine);
1220#if defined (Q_OS_LINUX) && CONFIG_EGL && CONFIG_X11
1232 QString soft = qgetenv(
"LIBGL_ALWAYS_SOFTWARE");
1233 bool ignore = soft ==
"1" || soft.compare(
"true", Qt::CaseInsensitive) == 0;
1234 bool allow = qEnvironmentVariableIsEmpty(
"MYTHTV_NO_EGL") && !ignore;
1235 bool force = !qEnvironmentVariableIsEmpty(
"MYTHTV_FORCE_EGL");
1240 if (vendor.contains(
"nvidia", Qt::CaseInsensitive) && !
force)
1242 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Not requesting EGL for vendor '%1'").arg(vendor));
1244 else if (!vendor.isEmpty() ||
force)
1246 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Requesting EGL for vendor '%1'").arg(vendor));
1247 setenv(
"QT_XCB_GL_INTEGRATION",
"xcb_egl", 0);
1252#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1254 QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
1258 if (
auto display = CmdLine.
toString(
"display"); !display.isEmpty())
1269 if (forcevrr && !(gsyncchanged || freesyncchanged))
1270 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Variable refresh rate not adjusted");
Parent class for defining application command line parsers.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
QString GetHostName(void)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
double GetFloatSettingOnHost(const QString &key, const QString &host, double defaultval=0.0)
static bool s_freeSyncResetOnExit
static bool CompareRates(double First, double Second, double Precision=0.01)
Determine whether two rates are considered equal with the given precision.
static int FindBestMatch(const MythDisplayModes &Modes, const MythDisplayMode &Mode, double &TargetRate)
void SetRefreshRate(double Rate)
double AspectRatio() const
double RefreshRate() const
static uint64_t FindBestScreen(const DisplayModeMap &Map, int Width, int Height, double Rate)
static uint64_t CalcKey(QSize Size, double Rate)
static bool IsAvailable()
double GetPixelAspectRatio()
virtual bool SwitchToVideoMode(QSize Size, double Framerate)
void InitScreenBounds()
Get screen size from Qt while respecting the user's multiscreen settings.
QStringList GetDescription()
static void PauseForModeSwitch()
double EstimateVirtualAspectRatio()
Estimate the overall display aspect ratio for multi screen setups.
double GetAspectRatio(QString &Source, bool IgnoreModeOverride=false)
Returns current screen aspect ratio.
void SwitchToDesktop()
Return the screen to the original desktop video mode.
virtual void UpdateCurrentMode()
Retrieve screen details.
static void GeometryChanged(QRect Geometry)
MythDisplayRates GetRefreshRates(QSize Size)
static void ConfigureQtGUI(int SwapInterval, const MythCommandLineParser &CmdLine)
Shared static initialisation code for all MythTV GUI applications.
MythDisplayMode m_guiMode
double GetRefreshRate() const
bool SwitchToVideo(QSize Size, double Rate=0.0)
Switches to the resolution and refresh rate defined in the database for the specified video resolutio...
void PhysicalDPIChanged(qreal DPI)
static QScreen * GetDesiredScreen()
static void DebugScreen(QScreen *qScreen, const QString &Message)
virtual bool VideoModesAvailable()
static MythDisplay * Create(MythMainWindow *MainWindow)
Create a MythDisplay object appropriate for the current platform.
bool SwitchToGUI(bool Wait=false)
Switches to the GUI resolution.
virtual void ScreenChanged(QScreen *qScreen)
The actual screen in use has changed. We must use it.
MythDisplayModes m_videoModes
bool m_waitForModeChanges
void ScreenRemoved(QScreen *qScreen)
MythDisplayMode m_desktopMode
QScreen * GetCurrentScreen()
Return a pointer to the screen to use.
static void PrimaryScreenChanged(QScreen *qScreen)
void ScreenCountChanged(int Screens)
void ScreenAdded(QScreen *qScreen)
DisplayModeMap m_overrideVideoModes
double m_aspectRatioOverride
void CurrentScreenChanged(QScreen *qScreen)
void WaitForScreenChange()
virtual const MythDisplayModes & GetVideoModes()
static QString GetExtraScreenInfo(QScreen *qScreen)
void SetWidget(QWidget *MainWindow)
Set the QWidget and QWindow in use.
std::chrono::microseconds GetRefreshInterval(std::chrono::microseconds Fallback) const
MythDisplayMode m_videoMode
bool NextModeIsLarger(QSize Size)
Check whether the next mode is larger in size than the current mode.
static bool SpanAllScreens()
Return true if the MythTV windows should span all screens.
static int GetScreenCount()
void CurrentDPIChanged(qreal DPI)
MythHDRDesc GetHDRSupport() const
static QString GetEGLVendor(void)
static bool s_gsyncResetOnExit
static void ForceGSync(bool Enable)
Enable or disable GSync before the main window is created.
static MythHDRPtr Create(class MythDisplay *MDisplay, const MythHDRDesc &Desc)
static QRect GetGeometryOverride()
static bool WindowIsAlwaysFullscreen()
Return true if the current platform only supports fullscreen windows.
static bool GeometryIsOverridden()
static MythVRRPtr Create(class MythDisplay *MDisplay)
Create a concrete implementation of MythVRR suitable for the given Display.
static void SetQtX11Display(const QString &DisplayStr)
static const struct wl_interface * types[]
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::microseconds > microsecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
std::vector< MythDisplayMode > MythDisplayModes
std::vector< double > MythDisplayRates
std::shared_ptr< class MythHDR > MythHDRPtr
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
static eu8 clamp(eu8 value, eu8 low, eu8 high)