From cfe205f17db502b89462b550b2e41dc09a26381c Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Mon, 3 Feb 2025 22:07:52 +0200 Subject: [PATCH 1/2] qt: probe rhi asynchronously and cache the valid result for the next run Startup time is defined as the time it takes to start playing the initial item when the application is opened. Currently probing is done synchronously each time the interface starts. This is not ideal, as we don't expect the system to suddenly start supporting a particular graphics api. Obviously, due to hardware change or driver update or any reason this may change, so we still need to check that each time. In this case, the worst can happen is that `QQuickWindow` emits error and terminates the application (usually with an error message box) when the api is no longer supported. However, since the cached api is checked each time asynchronously, the next startup would be fine. This basically improves the startup performance, at the expense of causing an error and terminating the application (in the worst case) if the system suddenly starts not supporting once valid api. The worst case is a rare case, so I believe that this would be a good optimization. --- modules/gui/qt/qt.cpp | 99 ++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/modules/gui/qt/qt.cpp b/modules/gui/qt/qt.cpp index 81b5f2e30ff0..ab6b35cf8897 100644 --- a/modules/gui/qt/qt.cpp +++ b/modules/gui/qt/qt.cpp @@ -920,45 +920,6 @@ static void *Thread( void *obj ) QApplication app( argc, argv ); app.setProperty("initialStyle", app.style()->objectName()); -#if defined(_WIN32) - // NOTE: Qt Quick does not have a cross-API RHI fallback procedure (as of Qt 6.7.1). - // We have to manually pick a graphics api here, since the default graphics - // api (Direct3D 11.2) may not be supported. - - if (qEnvironmentVariableIsEmpty("QSG_RHI_BACKEND") && - qEnvironmentVariableIsEmpty("QT_QUICK_BACKEND") && - (QT_VERSION < QT_VERSION_CHECK(6, 4, 0) || !uint(qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER")))) - { - // If OS version is lower than Windows 8.1, and Qt version is lower than - // 6.6.0, do not take risk and use OpenGL (since probing is not available). - // If OS version is greater than or equal to Windows 8.1, and Qt version is - // lower than 6.6.0, take risk and do not use the fallback procedure. - // Qt in the contribs is already version 6.7.0, so this should not be a - // concern. - if ((QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) || - (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))) - { - // TODO: Probe D3D12 when it becomes the default. - // If probing is not available, use OpenGL as a compromise: - QSGRendererInterface::GraphicsApi graphicsApi = QSGRendererInterface::OpenGL; -#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) - QRhiD3D11InitParams params; - if (QRhi::probe(QRhi::D3D11, ¶ms)) - graphicsApi = QSGRendererInterface::Direct3D11; - else - { - QRhiGles2InitParams params1; - params1.fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); - if (!QRhi::probe(QRhi::OpenGLES2, ¶ms1)) - graphicsApi = QSGRendererInterface::Software; - delete params1.fallbackSurface; - } -#endif - QQuickWindow::setGraphicsApi(graphicsApi); - } - } -#endif - { // Install custom translator: const auto translator = new Translator(&app); @@ -995,6 +956,66 @@ static void *Thread( void *obj ) #endif QSettings::UserScope, "vlc", "vlc-qt-interface" ); +#if defined(_WIN32) + // NOTE: Qt Quick does not have a cross-API RHI fallback procedure (as of Qt 6.7.1). + // We have to manually pick a graphics api here, since the default graphics + // api (Direct3D 11.2) may not be supported. + static const auto probeRhi = []() -> QSGRendererInterface::GraphicsApi { + QSGRendererInterface::GraphicsApi graphicsApi = QSGRendererInterface::OpenGL; + // TODO: Probe D3D12 when it becomes the default. + QRhiD3D11InitParams params; + if (QRhi::probe(QRhi::D3D11, ¶ms)) + graphicsApi = QSGRendererInterface::Direct3D11; + else + { + QRhiGles2InitParams params1; + params1.fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + if (!QRhi::probe(QRhi::OpenGLES2, ¶ms1)) + graphicsApi = QSGRendererInterface::Software; + delete params1.fallbackSurface; + } + return graphicsApi; + }; + + if (qEnvironmentVariableIsEmpty("QSG_RHI_BACKEND") && + qEnvironmentVariableIsEmpty("QT_QUICK_BACKEND") && + (QT_VERSION < QT_VERSION_CHECK(6, 4, 0) || !uint(qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER")))) + { + static const char* const graphicsApiKey = "graphics-api"; + const QVariant graphicsApiValue = p_intf->mainSettings->value(graphicsApiKey); + // settings value can be string (ini file), do not use `typeId()`: + if (graphicsApiValue.isValid() && Q_LIKELY(graphicsApiValue.canConvert<int>())) + { + // A cached (by then) valid graphics api is found, use it: + QQuickWindow::setGraphicsApi(static_cast<QSGRendererInterface::GraphicsApi>(graphicsApiValue.value<int>())); + // Asynchronous re-probe to see if the cached graphics api is still applicable. + // If not, QQuickWindow is going to emit scene graph error, and the application is + // likely going to terminate. However, when the user starts the application again + // there will not be an error thanks to this. We can not prevent the error, as + // it is decided to not make compositor initializaation wait to not reduce the startup + // speed. Startup time is defined as the time it takes to start playing the initial + // item. Currently the player waits for the interface, and QQuickWindow initialization + // is therefore not enforced to be synchronous (`QWindow::setVisible(true)` which + // initializes the scene graph thus rhi is asynchronous). + QMetaObject::invokeMethod(&app, [settings = QPointer(p_intf->mainSettings)]() { + // We can not use `QQuickWindow::setGraphicsApi()` here, as QQuickWindow + // may have already tried to initialize the scene graph hence rhi. If the + // cached graphics api is not optimal or not available anymore, the next + // startup will use the refreshed value. That's the best we can do here + // without forcing QQuickWindow to wait (hence delaying startup). + assert(settings); + settings->setValue(graphicsApiKey, static_cast<int>(probeRhi())); + }, Qt::QueuedConnection); // Asynchronous, so probing here does not cause start-up slowdown. + } + else + { + const QSGRendererInterface::GraphicsApi graphicsApi = probeRhi(); + QQuickWindow::setGraphicsApi(graphicsApi); + p_intf->mainSettings->setValue(graphicsApiKey, static_cast<int>(graphicsApi)); + } + } +#endif + app.setApplicationDisplayName( qtr("VLC media player") ); if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) ) -- GitLab From dc9b65eb93a620255ec283dfdaffa38fb49af9b6 Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Wed, 5 Feb 2025 19:21:15 +0200 Subject: [PATCH 2/2] qt: probe vulkan before opengl on windows OpenGL support on Windows is notoriously bad. This is mostly relevant for Windows 7 where D3D11 is not available that OpenGL is picked. Latest display drivers available for Windows 7 appear to be supporting Vulkan 1.0, which is what Qt reportedly uses. --- modules/gui/qt/qt.cpp | 44 ++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/modules/gui/qt/qt.cpp b/modules/gui/qt/qt.cpp index ab6b35cf8897..f76deadf2e76 100644 --- a/modules/gui/qt/qt.cpp +++ b/modules/gui/qt/qt.cpp @@ -961,20 +961,42 @@ static void *Thread( void *obj ) // We have to manually pick a graphics api here, since the default graphics // api (Direct3D 11.2) may not be supported. static const auto probeRhi = []() -> QSGRendererInterface::GraphicsApi { - QSGRendererInterface::GraphicsApi graphicsApi = QSGRendererInterface::OpenGL; + std::optional<QSGRendererInterface::GraphicsApi> graphicsApi; // TODO: Probe D3D12 when it becomes the default. - QRhiD3D11InitParams params; - if (QRhi::probe(QRhi::D3D11, ¶ms)) - graphicsApi = QSGRendererInterface::Direct3D11; - else { - QRhiGles2InitParams params1; - params1.fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); - if (!QRhi::probe(QRhi::OpenGLES2, ¶ms1)) - graphicsApi = QSGRendererInterface::Software; - delete params1.fallbackSurface; + // D3D11 + QRhiD3D11InitParams params; + if (QRhi::probe(QRhi::D3D11, ¶ms)) + graphicsApi = QSGRendererInterface::Direct3D11; + } + + if (!graphicsApi) + { + // Vulkan + QVulkanInstance inst; + if (inst.create()) + { + QRhiVulkanInitParams params1; + params1.inst = &inst; + if (QRhi::probe(QRhi::Vulkan, ¶ms1)) + graphicsApi = QSGRendererInterface::Vulkan; + } } - return graphicsApi; + + if (!graphicsApi) + { + // OpenGL + QRhiGles2InitParams params2; + params2.fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + if (QRhi::probe(QRhi::OpenGLES2, ¶ms2)) + graphicsApi = QSGRendererInterface::OpenGL; + delete params2.fallbackSurface; + } + + if (!graphicsApi) + graphicsApi = QSGRendererInterface::Software; + + return *graphicsApi; }; if (qEnvironmentVariableIsEmpty("QSG_RHI_BACKEND") && -- GitLab