7 #include <QApplication>
8 #include <QElapsedTimer>
23 #ifdef USING_WAYLANDEXTRAS
47 #define LOC QString("Display: ")
93 #ifdef USING_WAYLANDEXTRAS
129 #if defined(Q_OS_WIN)
141 bool spanall =
false;
146 result.append(tr(
"Spanning %1 screens").arg(screencount));
147 result.append(tr(
"Total bounds") + QString(
"\t: %1x%2")
156 result.append(tr(
"Supported HDR formats\t: %1").arg(hdr.join(
",")));
158 result.append(tr(
"HDR mode switching is not available"));
159 if (
auto brightness =
m_hdrState->GetMaxLuminance(); brightness > 1.0)
160 result.append(tr(
"Max display brightness\t: %1 nits").arg(
static_cast<int>(brightness)));
165 result.append(tr(
"Variable refresh rate '%1': %2 %3")
167 m_vrrState->Enabled() ? tr(
"Enabled") : tr(
"Disabled"),
172 const auto screens = QGuiApplication::screens();
174 for (
auto *screen : qAsConst(screens))
179 auto id = QString(
"(%1)").arg(screen->manufacturer());
180 if (screen ==
current && !spanall)
181 result.append(tr(
"Current screen %1 %2:").arg(screen->name(),
id));
183 result.append(tr(
"Screen %1 %2:").arg(screen->name(),
id));
184 result.append(tr(
"Size") + QString(
"\t\t: %1mmx%2mm")
185 .arg(screen->physicalSize().width()).arg(screen->physicalSize().height()));
190 result.append(tr(
"Aspect ratio") + QString(
"\t: %1 (%2)")
191 .arg(aspect, 0,
'f', 3).arg(source));
194 result.append(tr(
"Current mode") + QString(
"\t: %1x%2@%3Hz")
200 result.append(tr(
"Available modes:"));
201 for (
auto it = modes.crbegin(); it != modes.crend(); ++it)
202 result.append(
" " + it->ToString());
221 auto *guiapp = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
222 if (guiapp ==
nullptr)
232 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Deleting");
262 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Have main widget");
266 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Have main window");
292 return QGuiApplication::screens().size();
333 QScreen* newscreen =
nullptr;
343 bool windowed =
GetMythDB()->GetBoolSetting(
"RunFrontendInWindow",
false) &&
349 QPoint point = windowed ?
override.topLeft() :
override.bottomRight();
350 QList screens = QGuiApplication::screens();
351 for (QScreen *screen : qAsConst(screens))
353 if (screen->geometry().contains(point))
356 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
357 "Geometry override places window in screen '%1'").arg(newscreen->name()));
366 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Using primary screen for multiscreen");
367 newscreen = QGuiApplication::primaryScreen();
374 QList screens = QGuiApplication::screens();
375 for (QScreen *screen : qAsConst(screens))
377 if (!name.isEmpty() && name == screen->name())
379 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found screen '%1'").arg(name));
389 int screen_num = name.toInt(&ok);
390 QList<QScreen *>screens = QGuiApplication::screens();
391 if (ok && (screen_num >= 0) && (screen_num < screens.size()))
393 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found screen number %1 (%2)")
394 .arg(name, screens[screen_num]->name()));
395 newscreen = screens[screen_num];
402 QScreen *primary = QGuiApplication::primaryScreen();
403 if (name.isEmpty() && primary)
405 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Defaulting to primary screen (%1)")
406 .arg(primary->name()));
408 else if (name !=
"-1" && primary)
410 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen '%1' not found, defaulting to primary screen (%2)")
411 .arg(name, primary->name()));
426 disconnect(
m_screen,
nullptr,
this,
nullptr);
437 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Qt screen pixel ratio changed to %1")
438 .arg(DPI, 2,
'f', 2,
'0'));
455 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen '%1' removed").arg(qScreen->name()));
461 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"New screen geometry: %1x%2+%3+%4")
462 .arg(Geo.width()).arg(Geo.height()).arg(Geo.left()).arg(Geo.top()));
488 m_physicalSize = QSize(
static_cast<int>(screen->physicalSize().width()),
489 static_cast<int>(screen->physicalSize().height()));
500 QString mfg = qScreen->manufacturer();
503 QString model = qScreen->model();
506 return QString(
"(Make: %1 Model: %2)").arg(mfg, model);
514 auto geom = qScreen->geometry();
515 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 screen '%2' %3")
517 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Qt screen pixel ratio: %1")
518 .arg(qScreen->devicePixelRatio(), 2,
'f', 2,
'0'));
519 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Geometry: %1x%2+%3+%4 Size(Qt): %5mmx%6mm")
520 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
521 .arg(qScreen->physicalSize().width()).arg(qScreen->physicalSize().height()));
523 if (qScreen->virtualGeometry() != geom)
525 geom = qScreen->virtualGeometry();
526 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Total virtual geometry: %1x%2+%3+%4")
527 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top()));
548 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Desktop video mode: %1x%2 %3Hz")
553 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Display is using sRGB colourspace");
555 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Display has custom colourspace");
567 double aspectratio = 0.0;
568 GetMythDB()->GetResolutionSetting(
"GuiVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
569 GetMythDB()->GetResolutionSetting(
"DisplaySize", mmwidth, mmheight);
573 pixelwidth = pixelheight = 0;
574 GetMythDB()->GetResolutionSetting(
"TVVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
578 for (
int i = 0;
true; ++i)
584 double iaspect = 0.0;
585 double oaspect = 0.0;
589 GetMythDB()->GetResolutionSetting(
"VidMode", iw, ih, iaspect, irate, i);
590 GetMythDB()->GetResolutionSetting(
"TVVidMode", ow, oh, oaspect, orate, i);
592 if ((!iw && !ih && qFuzzyIsNull(irate)) || !(ih && ow && oh))
596 MythDisplayMode scr(QSize(ow, oh), QSize(mmwidth, mmheight), oaspect, orate);
611 const auto screens = QGuiApplication::screens();
612 for (
auto * screen : qAsConst(screens))
614 auto dim = screen->geometry();
616 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Screen %1: %2x%3 %4")
617 .arg(screen->name()).arg(dim.width()).arg(dim.height()).arg(extra));
620 const auto * primary = QGuiApplication::primaryScreen();
623 if (!screens.empty())
624 primary = screens.front();
627 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Qt has no screens!");
632 LOG(VB_GUI, LOG_INFO,
LOC +QString(
"Primary screen: %1.").arg(primary->name()));
635 auto dim = primary->virtualSize();
636 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Total desktop dim: %1x%2, over %3 screen[s].")
637 .arg(dim.width()).arg(dim.height()).arg(numScreens));
641 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Using entire desktop."));
646 if (
GetMythDB()->GetBoolSetting(
"RunFrontendInWindow",
false))
648 LOG(VB_GUI, LOG_INFO,
LOC +
"Running in a window");
658 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Using screen %1: %2x%3 at %4+%5")
696 double targetrate = 0.0;
697 double aspectoverride = 0.0;
701 Size.width(), Size.height(), Rate);
708 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Found custom screen override %1x%2 Aspect %3")
709 .arg(next.
Width()).arg(next.
Height()).arg(aspectoverride));
715 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to match best refresh rate %1Hz")
716 .arg(Rate, 0,
'f', 3));
731 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Ignoring mode switch to %1Hz - VRR enabled")
732 .arg(Rate, 0,
'f', 3));
735 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Allowing mode switch with VRR enabled for new resolution");
741 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using current mode %1x%2@%3Hz")
746 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Trying mode %1x%2@%3Hz")
751 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to change mode to %1x%2@%3Hz")
762 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switched to %1x%2@%3Hz for video %4x%5")
764 .arg(
m_refreshRate, 0,
'f', 3).arg(Size.width()).arg(Size.height()));
780 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using %1x%2@%3Hz for GUI")
787 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to change mode to %1x%2@%3Hz")
797 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switched to %1x%2@%3Hz")
818 auto max = std::get<1>(range) > 60 ? std::get<1>(range) : 60;
831 auto targetrate =
static_cast<double>(NAN);
837 return modes[
static_cast<size_t>(match)].RefreshRates();
870 auto valid = [](
double Aspect) {
return (Aspect > 0.1 && Aspect < 10.0); };
876 Source = tr(
"Video mode override");
899 Source = tr(
"Multiscreen estimate");
910 if (valid(calculated))
912 if ((
override < 0.0) || !valid(detected))
914 Source = tr(
"Square pixels");
947 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Supported HDR formats: %1")
949 if (
auto brightness =
m_hdrState->GetMaxLuminance(); brightness > 1.0)
951 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Display reports max brightness of %1 nits")
952 .arg(
static_cast<int>(brightness)));
968 auto sortscreens = [](
const QScreen* First,
const QScreen* Second)
970 if (First->geometry().left() < Second->geometry().left())
972 if (First->geometry().top() < Second->geometry().top())
978 double result = 16.0 / 9.0;
980 QList<QScreen*> screens;
982 screens =
m_screen->virtualSiblings();
987 std::sort(screens.begin(), screens.end(), sortscreens);
988 QList<double> aspectratios;
989 QSize totalresolution;
994 for (
auto it = screens.constBegin() ; it != screens.constEnd(); ++it)
996 QRect geom = (*it)->geometry();
997 totalresolution += geom.size();
998 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"%1x%2+%3+%4 %5")
999 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
1000 .arg((*it)->physicalSize().width() / (*it)->physicalSize().height()));
1001 if (lastleft < geom.left())
1004 lastleft = geom.left();
1006 if (lasttop < geom.top())
1009 lasttop = geom.top();
1012 aspectratios << (*it)->physicalSize().width() / (*it)->physicalSize().height();
1017 if (!totalresolution.isEmpty())
1018 result =
static_cast<double>(totalresolution.width()) / totalresolution.height();
1020 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen layout: %1x%2").arg(rows).arg(columns));
1021 if (rows == columns)
1023 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Grid layout");
1025 else if (rows == 1 && columns > 1)
1027 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Horizontal layout");
1029 else if (columns == 1 && rows > 1)
1031 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Vertical layout");
1035 LOG(VB_GENERAL, LOG_INFO,
1036 LOC + QString(
"Unsupported layout - defaulting to %1 (%2/%3)")
1037 .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1042 double aspectratio = 0.0;
1043 double average = 0.0;
1045 for (
auto it2 = aspectratios.constBegin() ; it2 != aspectratios.constEnd(); ++it2, ++count)
1047 aspectratio += *it2;
1048 average = aspectratio / count;
1049 if (qAbs(*it2 - average) > 0.1)
1051 LOG(VB_GENERAL, LOG_INFO,
LOC +
1052 QString(
"Inconsistent aspect ratios - defaulting to %1 (%2/%3)")
1053 .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1058 aspectratio = (average * columns) / rows;
1059 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Estimated aspect ratio: %1")
1081 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Waiting for resolution change");
1084 timer.setSingleShot(
true);
1085 connect(&timer, &
QTimer::timeout, [](){
LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Timed out wating for screen change"); });
1101 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Waiting for new screen");
1104 timer.setSingleShot(
true);
1105 connect(&timer, &
QTimer::timeout, [](){
LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Timed out waiting for new screen"); });
1116 if (pauselengthinms)
1118 LOG(VB_GENERAL, LOG_INFO,
LOC +
1119 QString(
"Pausing %1ms for video mode switch").arg(pauselengthinms));
1122 timer.setSingleShot(
true);
1125 timer.start(pauselengthinms);
1135 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Available modes:");
1138 auto rates = (*it).RefreshRates();
1139 QStringList rateslist;
1140 for (
auto it2 = rates.crbegin(); it2 != rates.crend(); ++it2)
1141 rateslist.append(QString(
"%1").arg(*it2, 2,
'f', 2,
'0'));
1142 if (rateslist.empty())
1143 rateslist.append(
"Variable rate?");
1144 LOG(VB_PLAYBACK, LOG_INFO, QString(
"%1x%2\t%3")
1145 .arg((*it).Width()).arg((*it).Height()).arg(rateslist.join(
"\t")));
1157 auto forcevrr = CmdLine.
toBool(
"vrr");
1158 bool gsyncchanged =
false;
1159 bool freesyncchanged =
false;
1161 #ifdef USING_QTWEBENGINE
1162 QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
1166 QSurfaceFormat format;
1169 if (qEnvironmentVariableIsSet(
"MYTHTV_DEPTH"))
1172 int depth = std::clamp(qEnvironmentVariableIntValue(
"MYTHTV_DEPTH"), 6, 16);
1173 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Trying to force depth to '%1'").arg(depth));
1174 format.setRedBufferSize(depth);
1178 format.setDepthBufferSize(0);
1179 format.setStencilBufferSize(0);
1181 format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
1182 format.setProfile(QSurfaceFormat::CompatibilityProfile);
1183 format.setSwapInterval(SwapInterval);
1184 QSurfaceFormat::setDefaultFormat(format);
1189 QApplication::setDesktopSettingsAware(
false);
1192 #if defined (USING_DRM) && defined (USING_QTPRIVATEHEADERS)
1198 #ifdef USING_WAYLANDEXTRAS
1203 MythDRMDevice::SetupDRM(CmdLine);
1209 #if defined (Q_OS_LINUX) && defined (USING_EGL) && defined (USING_X11)
1221 QString soft = qgetenv(
"LIBGL_ALWAYS_SOFTWARE");
1222 bool ignore = soft ==
"1" || soft.compare(
"true", Qt::CaseInsensitive) == 0;
1223 bool allow = qEnvironmentVariableIsEmpty(
"MYTHTV_NO_EGL") && !ignore;
1224 bool force = !qEnvironmentVariableIsEmpty(
"MYTHTV_FORCE_EGL");
1229 if (vendor.contains(
"nvidia", Qt::CaseInsensitive) && !
force)
1231 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Not requesting EGL for vendor '%1'").arg(vendor));
1233 else if (!vendor.isEmpty() ||
force)
1235 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Requesting EGL for vendor '%1'").arg(vendor));
1236 setenv(
"QT_XCB_GL_INTEGRATION",
"xcb_egl", 0);
1241 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1243 QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
1247 if (
auto display = CmdLine.
toString(
"display"); !display.isEmpty())
1258 if (forcevrr && !(gsyncchanged || freesyncchanged))
1259 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Variable refresh rate not adjusted");