diff options
Diffstat (limited to 'src/core/web_engine_context.cpp')
-rw-r--r-- | src/core/web_engine_context.cpp | 813 |
1 files changed, 533 insertions, 280 deletions
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 41aed57e2..faf9bd542 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -1,53 +1,20 @@ -/**************************************************************************** -** -** 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 <map> #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 +23,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 +37,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 +76,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) @@ -131,41 +106,221 @@ #include <QGuiApplication> #include <QMutex> #include <QOffscreenSurface> -#if QT_CONFIG(opengl) -#include <QOpenGLContext> -#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) +#include <QOpenGLContext> +#include <qopenglcontext_platform.h> + QT_BEGIN_NAMESPACE 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() +Q_LOGGING_CATEGORY(webEngineContextLog, "qt.webenginecontext") + +class GPUInfo { +public: + enum Vendor { + Unknown = -1, + AMD, + Apple, + ARM, + Google, + ImgTec, + Intel, + Microsoft, + Mesa, + Nvidia, + Qualcomm, + Samsung + }; + + static GPUInfo *instance() + { + static GPUInfo instance; + return &instance; + } + + static Vendor vendorIdToVendor(quint64 vendorId) + { + // clang-format off + // Based on //third_party/dawn/src/dawn/gpu_info.json + static const std::map<quint64, Vendor> vendorIdMap = { + {0x0, Unknown}, + {0x1002, AMD}, + {0x106B, Apple}, + {0x13B5, ARM}, + {0x1AE0, Google}, + {0x1010, ImgTec}, + {0x8086, Intel}, + {0x10005, Mesa}, + {0x1414, Microsoft}, + {0x10DE, Nvidia}, + {0x5143, Qualcomm}, + {0x144D, Samsung} + }; + // clang-format on + + auto it = vendorIdMap.find(vendorId); + if (it != vendorIdMap.end()) + return it->second; + + qWarning() << "Unknown Vendor ID:" << QString("0x%1").arg(vendorId, 0, 16); + return Unknown; + } + + static Vendor deviceNameToVendor(QString deviceName) + { + // TODO: Test and add more vendors to the list. + if (deviceName.contains(QLatin1String("AMD"), Qt::CaseInsensitive)) + return AMD; + if (deviceName.contains(QLatin1String("Intel"), Qt::CaseInsensitive)) + return Intel; + if (deviceName.contains(QLatin1String("Nvidia"), Qt::CaseInsensitive)) + return Nvidia; + +#if defined(USE_OZONE) + if (deviceName.contains(QLatin1String("Mesa llvmpipe"))) + return Mesa; +#endif + +#if defined(Q_OS_MACOS) + if (deviceName.contains(QLatin1String("Apple"))) + return Apple; +#endif + + return Unknown; + } + + static std::string vendorToString(Vendor vendor) + { + // clang-format off + static const std::map<Vendor, std::string> vendorNameMap = { + {Unknown, "Unknown"}, + {AMD, "AMD"}, + {Apple, "Apple"}, + {ARM, "ARM"}, + {Google, "Google"}, + {ImgTec, "Img Tec"}, + {Intel, "Intel"}, + {Mesa, "Mesa"}, + {Microsoft, "Microsoft"}, + {Nvidia, "Nvidia"}, + {Qualcomm, "Qualcomm"}, + {Samsung, "Samsung"} + }; + // clang-format on + + auto it = vendorNameMap.find(vendor); + if (it != vendorNameMap.end()) + return it->second; + + Q_UNREACHABLE(); + return "Unknown"; + } + + Vendor vendor() const { return m_vendor; } + QString getAdapterLuid() const { return m_adapterLuid; } + +private: + GPUInfo() + { #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; + { + static const bool preferSoftwareDevice = + qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER"); + QRhiD3D11InitParams params; + QRhi::Flags flags; + if (preferSoftwareDevice) { + flags |= QRhi::PreferSoftwareRenderer; + } + QScopedPointer<QRhi> d3d11Rhi(QRhi::create(QRhi::D3D11, ¶ms, flags, nullptr)); + // mimic what QSGRhiSupport and QBackingStoreRhi does + if (!d3d11Rhi && !preferSoftwareDevice) { + flags |= QRhi::PreferSoftwareRenderer; + d3d11Rhi.reset(QRhi::create(QRhi::D3D11, ¶ms, flags, nullptr)); + } + if (d3d11Rhi) { + m_vendor = vendorIdToVendor(d3d11Rhi->driverInfo().vendorId); + + const QRhiD3D11NativeHandles *handles = + static_cast<const QRhiD3D11NativeHandles *>(d3d11Rhi->nativeHandles()); + Q_ASSERT(handles); + m_adapterLuid = + QString("%1,%2").arg(handles->adapterLuidHigh).arg(handles->adapterLuidLow); + } + } +#elif defined(Q_OS_MACOS) + { + QRhiMetalInitParams params; + QScopedPointer<QRhi> metalRhi( + QRhi::create(QRhi::Metal, ¶ms, QRhi::Flags(), nullptr)); + if (metalRhi) + m_vendor = deviceNameToVendor(metalRhi->driverInfo().deviceName); + } #endif -} -static bool usingDefaultSGBackend() +#if QT_CONFIG(opengl) + if (m_vendor == Unknown) { + QRhiGles2InitParams params; + params.fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + QScopedPointer<QRhi> glRhi( + QRhi::create(QRhi::OpenGLES2, ¶ms, QRhi::Flags(), nullptr)); + if (glRhi) + m_vendor = deviceNameToVendor(glRhi->driverInfo().deviceName); + } +#endif + +#if QT_CONFIG(webengine_vulkan) + if (m_vendor == Unknown) { + QVulkanInstance vulkanInstance; + vulkanInstance.setApiVersion(QVersionNumber(1, 1)); + if (vulkanInstance.create()) { + QRhiVulkanInitParams params; + params.inst = &vulkanInstance; + QScopedPointer<QRhi> vulkanRhi( + QRhi::create(QRhi::Vulkan, ¶ms, QRhi::Flags(), nullptr)); + if (vulkanRhi) { + // TODO: The primary GPU is not necessarily the one which is connected to the + // display in case of a Multi-GPU setup on Linux. This can be workarounded by + // installing the Mesa's Device Selection Layer, + // see https://www.phoronix.com/news/Mesa-20.1-Vulkan-Dev-Selection + // Try to detect this case and at least warn about it. + m_vendor = vendorIdToVendor(vulkanRhi->driverInfo().vendorId); + } + } + } +#endif + + if (m_vendor == Unknown) + qWarning("Unable to detect GPU vendor."); + } + + Vendor m_vendor = Unknown; + QString m_adapterLuid; +}; + +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 +340,186 @@ 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"; +} + #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:" << GPUInfo::vendorToString(GPUInfo::instance()->vendor()).c_str(); + 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 +546,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) @@ -446,11 +666,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 +700,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 +722,6 @@ WebEngineContext::~WebEngineContext() Q_ASSERT(!m_devtoolsServer); Q_ASSERT(!m_browserRunner); Q_ASSERT(m_profileAdapters.isEmpty()); - delete s_syncPointManager.fetchAndStoreRelaxed(nullptr); } WebEngineContext *WebEngineContext::current() @@ -582,18 +795,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) { @@ -645,7 +846,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"); @@ -671,16 +872,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)); @@ -697,8 +893,6 @@ 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); @@ -714,21 +908,69 @@ WebEngineContext::WebEngineContext() // 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 defined(USE_OZONE) + if (GPUInfo::instance()->vendor() == GPUInfo::Nvidia) { + disableFeatures.push_back(media::kVaapiVideoDecodeLinux.name); + parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferVideoFrames); + } + +#if QT_CONFIG(webengine_vulkan) + 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) +#endif // defined(USE_OZONE) + +#if defined(Q_OS_WIN) + if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11 + || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) { + const QString luid = GPUInfo::instance()->getAdapterLuid(); + if (!luid.isEmpty()) + parsedCommandLine->AppendSwitchASCII(switches::kUseAdapterLuid, luid.toStdString()); + } +#endif + initializeFeatureList(parsedCommandLine, enableFeatures, disableFeatures); GLContextHelper::initialize(); @@ -737,84 +979,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 +1075,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 +1086,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 +1098,6 @@ WebEngineContext::WebEngineContext() #endif content::WebUIControllerFactory::RegisterFactory(WebUIControllerFactoryQt::GetInstance()); - - logContext(glType, parsedCommandLine); } #if QT_CONFIG(webengine_printing_and_pdf) @@ -877,47 +1117,71 @@ 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() @@ -925,45 +1189,34 @@ 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 |