diff options
Diffstat (limited to 'src/core/web_engine_context.cpp')
-rw-r--r-- | src/core/web_engine_context.cpp | 701 |
1 files changed, 419 insertions, 282 deletions
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 2329d27e4..94110d51c 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -1,53 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "web_engine_context.h" #include <math.h> +#include <QtGui/private/qrhi_p.h> #include "base/base_switches.h" +#include "base/functional/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/power_monitor/power_monitor.h" #include "base/power_monitor/power_monitor_device_source.h" #include "base/run_loop.h" -#include "base/task/post_task.h" +#include "base/strings/string_split.h" #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/threading/thread_restrictions.h" @@ -56,6 +22,7 @@ #include "chrome/browser/media/webrtc/webrtc_log_uploader.h" #endif #include "chrome/common/chrome_switches.h" +#include "content/common/process_visibility_tracker.h" #include "content/gpu/gpu_child_thread.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/compositor/viz_process_transport_factory.h" @@ -69,29 +36,35 @@ #include "components/web_cache/browser/web_cache_manager.h" #include "content/app/mojo_ipc_support.h" #include "content/browser/devtools/devtools_http_handler.h" +#include "content/browser/gpu/gpu_main_thread_factory.h" +#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/scheduler/browser_task_executor.h" #include "content/browser/startup_data_impl.h" #include "content/browser/startup_helper.h" +#include "content/browser/utility_process_host.h" +#include "content/gpu/in_process_gpu_thread.h" #include "content/public/app/content_main.h" #include "content/public/app/content_main_runner.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#if QT_CONFIG(webengine_pepper_plugins) #include "content/public/browser/plugin_service.h" +#endif #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_features.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" -#include "content/public/common/network_service_util.h" +#include "content/renderer/in_process_renderer_thread.h" +#include "content/utility/in_process_utility_thread.h" #include "gpu/command_buffer/service/gpu_switches.h" -#include "gpu/command_buffer/service/sync_point_manager.h" +#include "gpu/config/gpu_finch_features.h" #include "media/audio/audio_manager.h" #include "media/base/media_switches.h" #include "mojo/core/embedder/embedder.h" #include "net/base/port_util.h" -#include "ppapi/buildflags/buildflags.h" #include "sandbox/policy/switches.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/network_switches.h" @@ -102,14 +75,15 @@ #include "ui/base/ui_base_features.h" #include "ui/events/event_switches.h" #include "ui/native_theme/native_theme_features.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/gl_switches.h" -#if defined(OS_WIN) +#if defined(Q_OS_WIN) #include "sandbox/win/src/sandbox_types.h" #include "content/public/app/sandbox_helper_win.h" -#endif // OS_WIN +#endif // Q_OS_WIN #if defined(Q_OS_MACOS) -#include "base/mac/foundation_util.h" +#include "base/apple/foundation_util.h" #endif #if QT_CONFIG(accessibility) @@ -136,11 +110,13 @@ #include <qopenglcontext_platform.h> #endif #include <QQuickWindow> +#include <QRegularExpression> #include <QStringList> #include <QSurfaceFormat> #include <QNetworkProxy> #include <QtGui/qpa/qplatformintegration.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtQuick/private/qsgrhisupport_p.h> #include <QLoggingCategory> #if QT_CONFIG(opengl) @@ -149,23 +125,19 @@ Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); QT_END_NAMESPACE #endif +#define STRINGIFY_LITERAL(x) #x +#define STRINGIFY_EXPANDED(x) STRINGIFY_LITERAL(x) + namespace QtWebEngineCore { -#if QT_CONFIG(opengl) -static bool usingANGLE() -{ -#if defined(Q_OS_WIN) - if (qt_gl_global_share_context()) - return qt_gl_global_share_context()->isOpenGLES(); - return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES; -#else - return false; -#endif -} +Q_LOGGING_CATEGORY(webEngineContextLog, "qt.webenginecontext") -static bool usingDefaultSGBackend() +static bool usingSupportedSGBackend() { - if (QQuickWindow::graphicsApi() != QSGRendererInterface::OpenGL) + if (QQuickWindow::graphicsApi() != QSGRendererInterface::OpenGL + && QQuickWindow::graphicsApi() != QSGRendererInterface::Vulkan + && QQuickWindow::graphicsApi() != QSGRendererInterface::Metal + && QQuickWindow::graphicsApi() != QSGRendererInterface::Direct3D11) return false; const QStringList args = QGuiApplication::arguments(); @@ -185,109 +157,254 @@ static bool usingDefaultSGBackend() if (device.isEmpty()) device = qEnvironmentVariable("QMLSCENE_DEVICE"); - return device.isEmpty(); + return device.isEmpty() || device == QLatin1String("rhi"); } +#if QT_CONFIG(opengl) bool usingSoftwareDynamicGL() { + const char openGlVar[] = "QT_OPENGL"; if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) return true; + + if (qEnvironmentVariableIsSet(openGlVar)) { + const QByteArray requested = qgetenv(openGlVar); + if (requested == "software") + return true; + } #if defined(Q_OS_WIN) HMODULE handle = QNativeInterface::QWGLContext::openGLModuleHandle(); wchar_t path[MAX_PATH]; DWORD size = GetModuleFileName(handle, path, MAX_PATH); QFileInfo openGLModule(QString::fromWCharArray(path, size)); - return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); + return openGLModule.fileName().contains(QLatin1String("opengl32sw"),Qt::CaseInsensitive); #else return false; #endif } -static const char *getGLType(bool enableGLSoftwareRendering) +static bool openGLPlatformSupport() { - const char *glType = nullptr; - const bool tryGL = (usingDefaultSGBackend() && !usingSoftwareDynamicGL() - && QGuiApplicationPrivate::platformIntegration()->hasCapability( - QPlatformIntegration::OpenGL)) - || enableGLSoftwareRendering; - if (tryGL) { - if (!qt_gl_global_share_context() || !qt_gl_global_share_context()->isValid()) { - qWarning("WebEngineContext used before QtWebEngineCore::initialize() or OpenGL context " - "creation failed."); - } else { - const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); - switch (sharedFormat.renderableType()) { - case QSurfaceFormat::OpenGL: - glType = gl::kGLImplementationDesktopName; - // Check if Core profile was requested and is supported. - if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) { -#ifdef Q_OS_MACOS - glType = gl::kGLImplementationCoreProfileName; + return QGuiApplicationPrivate::platformIntegration()->hasCapability( + QPlatformIntegration::OpenGL); +} + +static std::string getGLType(bool enableGLSoftwareRendering, bool disableGpu) +{ + const bool tryGL = + usingSupportedSGBackend() && !usingSoftwareDynamicGL() && openGLPlatformSupport(); + if (disableGpu || (!tryGL && !enableGLSoftwareRendering)) + return gl::kGLImplementationDisabledName; + +#if defined(Q_OS_MACOS) + return gl::kGLImplementationANGLEName; #else - qWarning("An OpenGL Core Profile was requested, but it is not supported " - "on the current platform. Falling back to a non-Core profile. " - "Note that this might cause rendering issues."); +#if defined(Q_OS_WIN) + if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11 + || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) { + return gl::kGLImplementationANGLEName; + } #endif - } - break; - case QSurfaceFormat::OpenGLES: - glType = usingANGLE() ? gl::kGLImplementationANGLEName - : gl::kGLImplementationEGLName; - break; - case QSurfaceFormat::OpenVG: - case QSurfaceFormat::DefaultRenderableType: - default: - // Shared contex created but no rederable type set. - qWarning("Unsupported rendering surface format. Please open bug report at " - "https://bugreports.qt.io"); - } + + if (!qt_gl_global_share_context() || !qt_gl_global_share_context()->isValid()) { + qWarning("WebEngineContext is used before QtWebEngineQuick::initialize() or OpenGL context " + "creation failed."); + return gl::kGLImplementationDisabledName; + } + + const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + + switch (sharedFormat.renderableType()) { + case QSurfaceFormat::OpenGL: + if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) { + qWarning("An OpenGL Core Profile was requested, but it is not supported " + "on the current platform. Falling back to a non-Core profile. " + "Note that this might cause rendering issues."); } + return gl::kGLImplementationDesktopName; + case QSurfaceFormat::OpenGLES: + return gl::kGLImplementationEGLName; + case QSurfaceFormat::OpenVG: + case QSurfaceFormat::DefaultRenderableType: + default: + // Shared contex created but no rederable type set. + qWarning("Unsupported rendering surface format. Please open bug report at " + "https://bugreports.qt.io"); } - return glType; + + return gl::kGLImplementationDisabledName; +#endif // defined(Q_OS_MACOS) } #else -static const char *getGLType(bool enableGLSoftwareRendering) +static std::string getGLType(bool /*enableGLSoftwareRendering*/, bool disableGpu) { - return nullptr; + if (disableGpu) + return gl::kGLImplementationDisabledName; +#if defined(Q_OS_MACOS) + return gl::kGLImplementationANGLEName; +#elif defined(Q_OS_WIN) + if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11 + || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) { + return gl::kGLImplementationANGLEName; + } +#endif + return gl::kGLImplementationDisabledName; } #endif // QT_CONFIG(opengl) +static std::string getVulkanType(base::CommandLine *cmd) +{ +#if QT_CONFIG(webengine_vulkan) + if (cmd->HasSwitch(switches::kUseVulkan)) + return cmd->GetSwitchValueASCII(switches::kUseVulkan); +#endif + + return "disabled"; +} + +static std::string getAngleType(const std::string &glType, base::CommandLine *cmd) +{ + if (glType == gl::kGLImplementationANGLEName) { + if (cmd->HasSwitch(switches::kUseANGLE)) + return cmd->GetSwitchValueASCII(switches::kUseANGLE); + +#if defined(Q_OS_WIN) + return gl::kANGLEImplementationD3D11Name; +#elif defined(Q_OS_MACOS) + return gl::kANGLEImplementationMetalName; +#else + return gl::kANGLEImplementationDefaultName; +#endif + } + + return "disabled"; +} + +static quint64 getGPUVendorId() +{ +#if QT_CONFIG(webengine_vulkan) + QVulkanInstance vulkanInstance; + vulkanInstance.setApiVersion(QVersionNumber(1, 1)); + if (vulkanInstance.create()) { + QRhiVulkanInitParams params; + params.inst = &vulkanInstance; + QScopedPointer<QRhi> rhi(QRhi::create(QRhi::Vulkan, ¶ms, QRhi::Flags(), nullptr)); + return rhi->driverInfo().vendorId; + } +#endif + + return 0; +} + +#if defined(Q_OS_WIN) +static QString getAdapterLuid() { + static const bool preferSoftwareDevice = qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER"); + QRhiD3D11InitParams rhiParams; + QRhi::Flags flags; + if (preferSoftwareDevice) { + flags |= QRhi::PreferSoftwareRenderer; + } + QScopedPointer<QRhi> rhi(QRhi::create(QRhi::D3D11,&rhiParams,flags,nullptr)); + // mimic what QSGRhiSupport and QBackingStoreRhi does + if (!rhi && !preferSoftwareDevice) { + flags |= QRhi::PreferSoftwareRenderer; + rhi.reset(QRhi::create(QRhi::D3D11, &rhiParams, flags)); + } + if (rhi) { + const QRhiD3D11NativeHandles *handles = + static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles()); + Q_ASSERT(handles); + return QString("%1,%2").arg(handles->adapterLuidHigh).arg(handles->adapterLuidLow); + } else { + return QString(); + } +} +#endif + #if QT_CONFIG(webengine_pepper_plugins) void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&) { } #endif -static void logContext(const char *glType, base::CommandLine *cmd) +static void logContext(const std::string &glType, base::CommandLine *cmd) { - QLoggingCategory webEngineContextLog("qt.webenginecontext"); - if (webEngineContextLog.isInfoEnabled()) { + if (Q_UNLIKELY(webEngineContextLog().isDebugEnabled())) { + QStringList log; + log << "\n"; + + log << "Chromium GL Backend:" << glType.c_str() << "\n"; + log << "Chromium ANGLE Backend:" << getAngleType(glType, cmd).c_str() << "\n"; + log << "Chromium Vulkan Backend:" << getVulkanType(cmd).c_str() << "\n"; + log << "\n"; + + log << "QSG RHI Backend:" << QSGRhiSupport::instance()->rhiBackendName() << "\n"; + log << "QSG RHI Backend Supported:" << (usingSupportedSGBackend() ? "yes" : "no") << "\n"; + log << "GPU Vendor:"; + if (quint64 vendorId = getGPUVendorId()) { + switch (vendorId) { + case 0x1002: + log << "AMD"; + break; + case 0x10DE: + log << "NVIDIA"; + break; + case 0x8086: + log << "Intel"; + break; + case 0x1010: + log << "ImgTec"; + break; + case 0x13B5: + log << "ARM"; + break; + case 0x5143: + log << "Qualcomm"; + break; + default: + break; + } + log << QString("(0x%1)\n").arg(vendorId, 0, 16); + } else { + log << "Unable to detect\n"; + } + log << "\n"; + #if QT_CONFIG(opengl) - const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); - const auto profile = QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey( - sharedFormat.profile()); - const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey( - sharedFormat.renderableType()); - const base::CommandLine::SwitchMap switch_map = cmd->GetSwitches(); - QStringList params; - for (const auto &pair : switch_map) - params << " * " << toQt(pair.first) - << toQt(pair.second) << "\n"; - qCInfo(webEngineContextLog, - "\n\nGLImplementation: %s\n" - "Surface Type: %s\n" - "Surface Profile: %s\n" - "Surface Version: %d.%d\n" - "Using Default SG Backend: %s\n" - "Using Software Dynamic GL: %s\n" - "Using Angle: %s\n\n" - "Init Parameters:\n %s", - glType, type, profile, sharedFormat.majorVersion(), sharedFormat.minorVersion(), - usingDefaultSGBackend() ? "yes" : "no", usingSoftwareDynamicGL() ? "yes" : "no", - usingANGLE() ? "yes" : "no", qPrintable(params.join(" "))); -#else - qCInfo(webEngineContextLog) << "WebEngine compiled with no opengl enabled."; -#endif //QT_CONFIG(opengl) +#if defined(USE_OZONE) + log << "Using GLX:" << (GLContextHelper::getGlxPlatformInterface() ? "yes" : "no") << "\n"; + log << "Using EGL:" << (GLContextHelper::getEglPlatformInterface() ? "yes" : "no") << "\n"; +#endif + log << "Using Shared GL:" << (qt_gl_global_share_context() ? "yes" : "no") << "\n"; + if (qt_gl_global_share_context()) { + log << "Using Software Dynamic GL:" << (usingSoftwareDynamicGL() ? "yes" : "no") + << "\n"; + + const QSurfaceFormat sharedFormat = qt_gl_global_share_context() + ? qt_gl_global_share_context()->format() + : QSurfaceFormat::defaultFormat(); + const auto profile = + QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey( + sharedFormat.profile()); + const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey( + sharedFormat.renderableType()); + log << "Surface Type:" << type << "\n"; + log << "Surface Profile:" << profile << "\n"; + log << "Surface Version:" + << QString("%1.%2") + .arg(sharedFormat.majorVersion()) + .arg(sharedFormat.minorVersion()) + << "\n"; + } + log << "\n"; +#endif // QT_CONFIG(opengl) + + log << "Init Parameters:\n"; + const base::CommandLine::SwitchMap switchMap = cmd->GetSwitches(); + for (const auto &pair : switchMap) + log << " * " << toQt(pair.first) << toQt(pair.second) << "\n"; + + qCDebug(webEngineContextLog) << qPrintable(log.join(" ")); } } @@ -314,26 +431,14 @@ static void setupProxyPac(base::CommandLine *commandLine) } } -static bool waitForViz = false; -static void completeVizCleanup() -{ - waitForViz = false; -} - static void cleanupVizProcess() { auto gpuChildThread = content::GpuChildThread::instance(); if (!gpuChildThread) return; - auto vizMain = gpuChildThread->viz_main(); - auto vizCompositorThreadRunner = vizMain->viz_compositor_thread_runner(); - if (!vizCompositorThreadRunner) - return; - waitForViz = true; content::GetHostFrameSinkManager()->SetConnectionLostCallback(base::DoNothing()); auto factory = static_cast<content::VizProcessTransportFactory*>(content::ImageTransportFactory::GetInstance()); factory->PrepareForShutDown(); - vizCompositorThreadRunner->CleanupForShutdown(base::BindOnce(&completeVizCleanup)); } static QStringList parseEnvCommandLine(const QString &cmdLine) @@ -384,7 +489,7 @@ static QStringList parseEnvCommandLine(const QString &cmdLine) scoped_refptr<QtWebEngineCore::WebEngineContext> WebEngineContext::m_handle; bool WebEngineContext::m_destroyed = false; - +bool WebEngineContext::m_closingDown = false; void WebEngineContext::destroyProfileAdapter() { if (content::RenderProcessHost::run_renderer_in_process()) { @@ -446,11 +551,6 @@ void WebEngineContext::destroy() // on IO thread (triggered by ~BrowserMainRunner). But by that time the UI // task runner is not working anymore so we need to do this earlier. cleanupVizProcess(); - while (waitForViz) { - flushMessages(); - QThread::msleep(50); - } - destroyGpuProcess(); // Flush the UI message loop before quitting. flushMessages(); @@ -485,7 +585,6 @@ void WebEngineContext::destroy() GLContextHelper::destroy(); // These would normally be in the content-runner, but we allocated them separately: - m_startupData.reset(); m_mojoIpcSupport.reset(); m_discardableSharedMemoryManager.reset(); @@ -508,7 +607,6 @@ WebEngineContext::~WebEngineContext() Q_ASSERT(!m_devtoolsServer); Q_ASSERT(!m_browserRunner); Q_ASSERT(m_profileAdapters.isEmpty()); - delete s_syncPointManager.fetchAndStoreRelaxed(nullptr); } WebEngineContext *WebEngineContext::current() @@ -553,6 +651,7 @@ void WebEngineContext::destroyContextPostRoutine() // Destroy WebEngineContext before its static pointer is zeroed and destructor called. // Before destroying MessageLoop via destroying BrowserMainRunner destructor // WebEngineContext's pointer is used. + m_closingDown = true; m_handle->destroy(); #if !defined(NDEBUG) if (!m_handle->HasOneRef()) @@ -581,18 +680,6 @@ ProxyAuthentication WebEngineContext::qProxyNetworkAuthentication(QString host, const static char kChromiumFlagsEnv[] = "QTWEBENGINE_CHROMIUM_FLAGS"; const static char kDisableSandboxEnv[] = "QTWEBENGINE_DISABLE_SANDBOX"; -const static char kDisableInProcGpuThread[] = "QTWEBENGINE_DISABLE_GPU_THREAD"; - -// static -bool WebEngineContext::isGpuServiceOnUIThread() -{ - static bool threadedGpu = -#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS) - QOpenGLContext::supportsThreadedOpenGL() && -#endif - !qEnvironmentVariableIsSet(kDisableInProcGpuThread); - return !threadedGpu; -} static void initializeFeatureList(base::CommandLine *commandLine, std::vector<std::string> enableFeatures, std::vector<std::string> disableFeatures) { @@ -644,7 +731,7 @@ WebEngineContext::WebEngineContext() #if defined(Q_OS_MACOS) // The bundled handling is currently both completely broken in Chromium, // and unnecessary for us. - base::mac::SetOverrideAmIBundled(false); + base::apple::SetOverrideAmIBundled(false); #endif base::ThreadPoolInstance::Create("Browser"); @@ -670,16 +757,11 @@ WebEngineContext::WebEngineContext() // Allow us to inject javascript like any webview toolkit. content::RenderFrameHost::AllowInjectingJavaScript(); - QStringList appArgs = QCoreApplication::arguments(); - bool useEmbeddedSwitches = false; -#if defined(QTWEBENGINE_EMBEDDED_SWITCHES) - useEmbeddedSwitches = !appArgs.contains(QStringLiteral("--disable-embedded-switches")); -#else - useEmbeddedSwitches = appArgs.contains(QStringLiteral("--enable-embedded-switches")); -#endif + bool enableGLSoftwareRendering = false; + base::CommandLine *parsedCommandLine = + initCommandLine(useEmbeddedSwitches, enableGLSoftwareRendering); - base::CommandLine* parsedCommandLine = commandLine(); setupProxyPac(parsedCommandLine); parsedCommandLine->AppendSwitchPath(switches::kBrowserSubprocessPath, WebEngineLibraryInfo::getPath(content::CHILD_PROCESS_EXE)); @@ -696,39 +778,77 @@ WebEngineContext::WebEngineContext() qInfo() << "Sandboxing disabled by user."; } - parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing); - // Do not advertise a feature we have removed at compile time parsedCommandLine->AppendSwitch(switches::kDisableSpeechAPI); std::vector<std::string> disableFeatures; std::vector<std::string> enableFeatures; + enableFeatures.push_back(features::kNetworkServiceInProcess.name); enableFeatures.push_back(features::kTracingServiceInProcess.name); - disableFeatures.push_back(network::features::kDnsOverHttpsUpgrade.name); - // When enabled, event.movement is calculated in blink instead of in browser. disableFeatures.push_back(features::kConsolidatedMovementXY.name); // Avoid crashing when websites tries using this feature (since 83) disableFeatures.push_back(features::kInstalledApp.name); + // Not implemented but it overrides the devtools eyedropper + // Should be sync with kEyeDropper base::Feature + parsedCommandLine->AppendSwitchASCII(switches::kDisableBlinkFeatures, "EyeDropperAPI"); + disableFeatures.push_back(features::kEyeDropper.name); + // Explicitly tell Chromium about default-on features we do not support disableFeatures.push_back(features::kBackgroundFetch.name); disableFeatures.push_back(features::kWebOTP.name); disableFeatures.push_back(features::kWebPayments.name); disableFeatures.push_back(features::kWebUsb.name); - disableFeatures.push_back(media::kPictureInPicture.name); if (useEmbeddedSwitches) { // embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc enableFeatures.push_back(features::kOverlayScrollbar.name); parsedCommandLine->AppendSwitch(switches::kEnableViewport); - parsedCommandLine->AppendSwitch(switches::kMainFrameResizesAreOrientationChanges); parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing); } +#if QT_CONFIG(webengine_vulkan) && defined(USE_OZONE) + if (QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) { + enableFeatures.push_back(features::kVulkan.name); + parsedCommandLine->AppendSwitchASCII(switches::kUseVulkan, + switches::kVulkanImplementationNameNative); + const char deviceExtensionsVar[] = "QT_VULKAN_DEVICE_EXTENSIONS"; + QByteArrayList requiredDeviceExtensions = { "VK_KHR_external_memory_fd", + "VK_EXT_external_memory_dma_buf", + "VK_EXT_image_drm_format_modifier" }; + if (qEnvironmentVariableIsSet(deviceExtensionsVar)) { + QByteArrayList envExtList = qgetenv(deviceExtensionsVar).split(';'); + int found = 0; + for (const QByteArray &ext : requiredDeviceExtensions) { + if (envExtList.contains(ext)) + found++; + } + if (found != requiredDeviceExtensions.size()) { + qWarning().nospace() + << "Vulkan rendering may fail because " << deviceExtensionsVar + << " environment variable is already set but it doesn't contain" + << " some of the required Vulkan device extensions:\n" + << qPrintable(requiredDeviceExtensions.join('\n')); + } + } else { + qputenv(deviceExtensionsVar, requiredDeviceExtensions.join(';')); + } + } +#endif // QT_CONFIG(webengine_vulkan) && defined(USE_OZONE) + +#if defined(Q_OS_WIN) + if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11 + || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) { + const QString luid = getAdapterLuid(); + if (!luid.isEmpty()) + parsedCommandLine->AppendSwitchASCII(switches::kUseAdapterLuid, luid.toStdString()); + } +#endif + initializeFeatureList(parsedCommandLine, enableFeatures, disableFeatures); GLContextHelper::initialize(); @@ -737,84 +857,91 @@ WebEngineContext::WebEngineContext() // bitmaps, use software rendering via software OpenGL. This might be less // performant, but at least provides WebGL support. // TODO(miklocek), check if this still works with latest chromium - const bool enableGLSoftwareRendering = appArgs.contains(QStringLiteral("--enable-webgl-software-rendering")); - const char *glType = getGLType(enableGLSoftwareRendering); - - if (glType) { -#if QT_CONFIG(opengl) + const bool disableGpu = parsedCommandLine->HasSwitch(switches::kDisableGpu); + std::string glType; + if (parsedCommandLine->HasSwitch(switches::kUseGL)) + glType = parsedCommandLine->GetSwitchValueASCII(switches::kUseGL); + else { + glType = getGLType(enableGLSoftwareRendering, disableGpu); parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); - parsedCommandLine->AppendSwitch(switches::kInProcessGPU); + } + + parsedCommandLine->AppendSwitch(switches::kInProcessGPU); + + if (glType != gl::kGLImplementationDisabledName) { if (enableGLSoftwareRendering) { parsedCommandLine->AppendSwitch(switches::kDisableGpuRasterization); parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlocklist); } - const QSurfaceFormat sharedFormat = QOpenGLContext::globalShareContext()->format(); - if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile) - parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext); +#if QT_CONFIG(opengl) + if (glType != gl::kGLImplementationANGLEName) { + QOpenGLContext *shareContext = QOpenGLContext::globalShareContext(); + Q_ASSERT(shareContext); + const QSurfaceFormat sharedFormat = shareContext->format(); + if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile) + parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext); #if defined(Q_OS_WIN) - // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create - // an OpenGL Core Profile context. If the switch is not set, it would always try to create a - // Core Profile context, even if Qt uses a legacy profile, which causes - // "Could not share GL contexts" warnings, because it's not possible to share between Core and - // legacy profiles. See GLContextWGL::Initialize(). - // Given that Desktop GL Core profile is not currently supported on Windows anyway, pass this - // switch to get rid of the warnings. - // - // The switch is also used to determine which version of OpenGL ES to use (2 or 3) when using - // ANGLE. - // If the switch is not set, Chromium will always try to create an ES3 context, even if Qt uses - // an ES2 context, which causes resource sharing issues (black screen), - // see gpu::gles2::GenerateGLContextAttribs(). - // Make sure to disable ES3 context creation when using ES2. - const bool isGLES2Context = QOpenGLContext::globalShareContext()->isOpenGLES() - && QOpenGLContext::globalShareContext()->format().majorVersion() == 2; - if (!usingANGLE() || isGLES2Context) - parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); + // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create + // an OpenGL Core Profile context. If the switch is not set, it would always try to create a + // Core Profile context, even if Qt uses a legacy profile, which causes + // "Could not share GL contexts" warnings, because it's not possible to share between Core and + // legacy profiles. See GLContextWGL::Initialize(). + if (sharedFormat.renderableType() == QSurfaceFormat::OpenGL + && sharedFormat.profile() != QSurfaceFormat::CoreProfile) { + gl::GlWorkarounds workarounds = gl::GetGlWorkarounds(); + workarounds.disable_es3gl_context = true; + gl::SetGlWorkarounds(workarounds); + } #endif + } #endif //QT_CONFIG(opengl) - } else { + } else if (!disableGpu) { parsedCommandLine->AppendSwitch(switches::kDisableGpu); } + logContext(glType, parsedCommandLine); + registerMainThreadFactories(); content::ContentMainParams contentMainParams(m_mainDelegate.get()); -#if defined(OS_WIN) + contentMainParams.setup_signal_handlers = false; +#if defined(Q_OS_WIN) contentMainParams.sandbox_info = QtWebEngineSandbox::staticSandboxInterfaceInfo(); - sandbox::SandboxInterfaceInfo sandbox_info = {0}; + sandbox::SandboxInterfaceInfo sandbox_info = {nullptr}; if (!contentMainParams.sandbox_info) { content::InitializeSandboxInfo(&sandbox_info); contentMainParams.sandbox_info = &sandbox_info; } #endif - m_contentRunner->Initialize(contentMainParams); + m_contentRunner->Initialize(std::move(contentMainParams)); mojo::core::Configuration mojoConfiguration; mojoConfiguration.is_broker_process = true; mojo::core::Init(mojoConfiguration); - // This block mirrors ContentMainRunnerImpl::RunServiceManager(): - m_mainDelegate->PreCreateMainMessageLoop(); + // This block mirrors ContentMainRunnerImpl::RunBrowser(): + m_mainDelegate->PreBrowserMain(); base::MessagePump::OverrideMessagePumpForUIFactory(messagePumpFactory); content::BrowserTaskExecutor::Create(); - m_mainDelegate->PostEarlyInitialization(false); + m_mainDelegate->PostEarlyInitialization({}); content::StartBrowserThreadPool(); content::BrowserTaskExecutor::PostFeatureListSetup(); - tracing::InitTracingPostThreadPoolStartAndFeatureList(); - m_discardableSharedMemoryManager = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>(); + tracing::InitTracingPostThreadPoolStartAndFeatureList(false); base::PowerMonitor::Initialize(std::make_unique<base::PowerMonitorDeviceSource>()); + content::ProcessVisibilityTracker::GetInstance(); + m_discardableSharedMemoryManager = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>(); m_mojoIpcSupport = std::make_unique<content::MojoIpcSupport>(content::BrowserTaskExecutor::CreateIOThread()); download::SetIOTaskRunner(m_mojoIpcSupport->io_thread()->task_runner()); - m_startupData = m_mojoIpcSupport->CreateBrowserStartupData(); + std::unique_ptr<content::StartupData> startupData = m_mojoIpcSupport->CreateBrowserStartupData(); // Once the MessageLoop has been created, attach a top-level RunLoop. m_runLoop.reset(new base::RunLoop); m_runLoop->BeforeRun(); - content::MainFunctionParams mainParams(*base::CommandLine::ForCurrentProcess()); - mainParams.startup_data = m_startupData.get(); - m_browserRunner->Initialize(mainParams); + content::MainFunctionParams mainParams(base::CommandLine::ForCurrentProcess()); + mainParams.startup_data = std::move(startupData); + m_browserRunner->Initialize(std::move(mainParams)); m_devtoolsServer.reset(new DevToolsServerQt()); m_devtoolsServer->start(); @@ -826,14 +953,7 @@ WebEngineContext::WebEngineContext() // Initialize WebCacheManager here to ensure its subscription to render process creation events. web_cache::WebCacheManager::GetInstance(); - base::ThreadRestrictions::SetIOAllowed(true); - - if (parsedCommandLine->HasSwitch(network::switches::kExplicitlyAllowedPorts)) { - std::string allowedPorts = parsedCommandLine->GetSwitchValueASCII(network::switches::kExplicitlyAllowedPorts); - net::SetExplicitlyAllowedPorts(allowedPorts); - } - -#if defined(OS_LINUX) +#if defined(Q_OS_LINUX) media::AudioManager::SetGlobalAppName(QCoreApplication::applicationName().toStdString()); #endif @@ -844,7 +964,7 @@ WebEngineContext::WebEngineContext() // be created from the FILE thread, and that GetPluginInfoArray is synchronous, it // can't loads plugins synchronously from the IO thread to serve the render process' request // and we need to make sure that it happened beforehand. - content::PluginService::GetInstance()->GetPlugins(base::Bind(&dummyGetPluginCallback)); + content::PluginService::GetInstance()->GetPlugins(base::BindOnce(&dummyGetPluginCallback)); #endif #if QT_CONFIG(webengine_printing_and_pdf) @@ -856,8 +976,6 @@ WebEngineContext::WebEngineContext() #endif content::WebUIControllerFactory::RegisterFactory(WebUIControllerFactoryQt::GetInstance()); - - logContext(glType, parsedCommandLine); } #if QT_CONFIG(webengine_printing_and_pdf) @@ -877,87 +995,106 @@ WebRtcLogUploader *WebEngineContext::webRtcLogUploader() #endif -static QMutex s_spmMutex; -QAtomicPointer<gpu::SyncPointManager> WebEngineContext::s_syncPointManager; - -gpu::SyncPointManager *WebEngineContext::syncPointManager() +base::CommandLine *WebEngineContext::initCommandLine(bool &useEmbeddedSwitches, + bool &enableGLSoftwareRendering) { - if (gpu::SyncPointManager *spm = s_syncPointManager.loadAcquire()) - return spm; - QMutexLocker lock(&s_spmMutex); - if (!s_syncPointManager) - s_syncPointManager.storeRelaxed(new gpu::SyncPointManager()); - return s_syncPointManager.loadRelaxed(); -} + if (!base::CommandLine::CreateEmpty()) + qFatal("base::CommandLine has been initialized unexpectedly."); -base::CommandLine* WebEngineContext::commandLine() { - if (base::CommandLine::CreateEmpty()) { - base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); - QStringList appArgs = QCoreApplication::arguments(); - if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { - appArgs = appArgs.mid(0, 1); // Take application name and drop the rest - appArgs.append(parseEnvCommandLine(qEnvironmentVariable(kChromiumFlagsEnv))); + QStringList appArgs = QCoreApplication::arguments(); + if (appArgs.empty()) { + qFatal("Argument list is empty, the program name is not passed to QCoreApplication. " + "base::CommandLine cannot be properly initialized."); + } + + base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess(); + int index = appArgs.indexOf(QRegularExpression(QLatin1String("--webEngineArgs"), + QRegularExpression::CaseInsensitiveOption)); + if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { + appArgs = appArgs.mid(0, 1); // Take application name and drop the rest + appArgs.append(parseEnvCommandLine(qEnvironmentVariable(kChromiumFlagsEnv))); + if (index > -1) + qWarning("Note 'webEngineArgs' are overridden by QTWEBENGINE_CHROMIUM_FLAGS"); + } else { + if (index > -1) { + appArgs.erase(appArgs.begin() + 1, appArgs.begin() + index + 1); + } else { + appArgs = appArgs.mid(0, 1); } -#ifdef Q_OS_WIN - appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); + } +#if defined(QTWEBENGINE_EMBEDDED_SWITCHES) + useEmbeddedSwitches = !appArgs.contains(QStringLiteral("--disable-embedded-switches")); +#else + useEmbeddedSwitches = appArgs.contains(QStringLiteral("--enable-embedded-switches")); #endif - appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); - appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); + enableGLSoftwareRendering = + appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); + appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); + appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); + + bool isRemoteDebugPort = + (-1 + != appArgs.indexOf(QRegularExpression(QStringLiteral("--remote-debugging-port=.*"), + QRegularExpression::CaseInsensitiveOption))) + || !qEnvironmentVariable("QTWEBENGINE_REMOTE_DEBUGGING").isEmpty(); + bool isRemoteAllowOrigins = + (-1 + != appArgs.indexOf(QRegularExpression(QStringLiteral("--remote-allow-origins=.*"), + QRegularExpression::CaseInsensitiveOption))); + + if (isRemoteDebugPort && !isRemoteAllowOrigins) { + appArgs.append(QStringLiteral("--remote-allow-origins=*")); + qWarning("Added {--remote-allow-origins=*} to command-line arguments " + "to avoid web socket connection errors during remote debugging."); + } - base::CommandLine::StringVector argv; - argv.resize(appArgs.size()); + base::CommandLine::StringVector argv; + argv.resize(appArgs.size()); #if defined(Q_OS_WIN) - for (int i = 0; i < appArgs.size(); ++i) - argv[i] = toString16(appArgs[i]); + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = appArgs[i].toStdWString(); #else - for (int i = 0; i < appArgs.size(); ++i) - argv[i] = appArgs[i].toStdString(); + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = appArgs[i].toStdString(); #endif - parsedCommandLine->InitFromArgv(argv); - return parsedCommandLine; - } else { - return base::CommandLine::ForCurrentProcess(); - } + parsedCommandLine->InitFromArgv(argv); + + return parsedCommandLine; +} + +bool WebEngineContext::closingDown() +{ + return m_closingDown; +} + +void WebEngineContext::registerMainThreadFactories() +{ + content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); + content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); + content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread); } } // namespace QT_BEGIN_NAMESPACE -/*! - \relates <qtwebenginecoreglobal.h> - \since 6.2 - - Returns the version number of Qt WebEngine at run-time as a string - (for example, "6.2.0"). This may be a different version than the - version the application was compiled against, and a different version - than Qt. -*/ const char *qWebEngineVersion() noexcept { - return QTWEBENGINECORE_VERSION_STR; + return STRINGIFY_EXPANDED(QTWEBENGINECORE_VERSION_STR); } -/*! - \relates <qtwebenginecoreglobal.h> - \since 6.2 +const char *qWebEngineProcessName() noexcept +{ + return STRINGIFY_EXPANDED(QTWEBENGINEPROCESS_NAME); +} - Returns the version number of Chromium used by Qt WebEngine at run-time - as a string (for example, "83.0.4103.122"). -*/ const char *qWebEngineChromiumVersion() noexcept { - return CHROMIUM_VERSION; + return STRINGIFY_EXPANDED(CHROMIUM_VERSION); } -/*! - \relates <qtwebenginecoreglobal.h> - \since 6.3 - - Returns the version number of last Chromium version security patches have been - merged from. -*/ const char *qWebEngineChromiumSecurityPatchVersion() noexcept { - return "92.0.4515.166"; // FIXME: Remember to update + return "122.0.6261.128"; // FIXME: Remember to update } + QT_END_NAMESPACE |