diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 9585609f0..64965e128 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -37,6 +37,9 @@ Changed (like `:config-cycle`). - QtWebEngine: On Qt 5.11.1, no reloads are needed anymore when switching between pages with changed settings (e.g. `content.javascript.enabled`). +- The `qt.force_software_rendering` setting changed from a boolean to taking + different values (`software-opengl`, `qt-quick` and `chromium`) for different + kinds of software rendering workarounds. v1.3.2 (unreleased) ------------------- diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index c87d13d88..6d20fcf2d 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -2579,12 +2579,19 @@ Default: empty [[qt.force_software_rendering]] === qt.force_software_rendering Force software rendering for QtWebEngine. -This is needed for QtWebEngine to work with Nouveau drivers. +This is needed for QtWebEngine to work with Nouveau drivers and can be useful in other scenarios related to graphic issues. This setting requires a restart. -Type: <> +Type: <> -Default: +pass:[false]+ +Valid values: + + * +software-opengl+: Tell LibGL to use a software implementation of GL (`LIBGL_ALWAYS_SOFTWARE` / `QT_XCB_FORCE_SOFTWARE_OPENGL`) + * +qt-quick+: Tell Qt Quick to use a software renderer instead of OpenGL. (`QT_QUICK_BACKEND=software`) + * +chromium+: Tell Chromium to disable GPU support and use Skia software rendering instead. (`--disable-gpu`) + * +none+: Don't force software rendering. + +Default: +pass:[none]+ This setting is only available with the QtWebEngine backend. diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 78bb48c16..ab7a38309 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -150,14 +150,24 @@ force_software_rendering: renamed: qt.force_software_rendering qt.force_software_rendering: - type: Bool - default: false + type: + name: String + valid_values: + - software-opengl: Tell LibGL to use a software implementation of GL + (`LIBGL_ALWAYS_SOFTWARE` / `QT_XCB_FORCE_SOFTWARE_OPENGL`) + - qt-quick: Tell Qt Quick to use a software renderer instead of OpenGL. + (`QT_QUICK_BACKEND=software`) + - chromium: Tell Chromium to disable GPU support and use Skia software + rendering instead. (`--disable-gpu`) + - none: Don't force software rendering. + default: none backend: QtWebEngine restart: true desc: >- Force software rendering for QtWebEngine. - This is needed for QtWebEngine to work with Nouveau drivers. + This is needed for QtWebEngine to work with Nouveau drivers and can be + useful in other scenarios related to graphic issues. qt.force_platform: type: diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index 25c0c9971..47034a535 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -277,6 +277,15 @@ class YamlConfig(QObject): settings[name][scope] = 'always' if val else 'never' self._mark_changed() + # qt.force_software_rendering isn't a boolean anymore + name = 'qt.force_software_rendering' + if name in settings: + for scope, val in settings[name].items(): + if isinstance(val, bool): + settings[name][scope] = ('software-opengl' if val + else 'none') + self._mark_changed() + return settings def _validate(self, settings): diff --git a/qutebrowser/config/configinit.py b/qutebrowser/config/configinit.py index 1f9f0f4b6..747803ced 100644 --- a/qutebrowser/config/configinit.py +++ b/qutebrowser/config/configinit.py @@ -83,9 +83,12 @@ def early_init(args): def _init_envvars(): """Initialize environment variables which need to be set early.""" - if (objects.backend == usertypes.Backend.QtWebEngine and - config.val.qt.force_software_rendering): - os.environ['QT_XCB_FORCE_SOFTWARE_OPENGL'] = '1' + if objects.backend == usertypes.Backend.QtWebEngine: + software_rendering = config.val.qt.force_software_rendering + if software_rendering == 'software-opengl': + os.environ['QT_XCB_FORCE_SOFTWARE_OPENGL'] = '1' + elif software_rendering == 'qt-quick': + os.environ['QT_QUICK_BACKEND'] = 'software' if config.val.qt.force_platform is not None: os.environ['QT_QPA_PLATFORM'] = config.val.qt.force_platform @@ -163,11 +166,13 @@ def qt_args(namespace): argv += ['--' + arg for arg in config.val.qt.args] - if (objects.backend == usertypes.Backend.QtWebEngine and - not qtutils.version_check('5.11', compiled=False)): - # WORKAROUND equivalent to - # https://codereview.qt-project.org/#/c/217932/ - # Needed for Qt < 5.9.5 and < 5.10.1 - argv.append('--disable-shared-workers') + if objects.backend == usertypes.Backend.QtWebEngine: + if not qtutils.version_check('5.11', compiled=False): + # WORKAROUND equivalent to + # https://codereview.qt-project.org/#/c/217932/ + # Needed for Qt < 5.9.5 and < 5.10.1 + argv.append('--disable-shared-workers') + if config.val.qt.force_software_rendering == 'chromium': + argv.append('--disable-gpu') return argv diff --git a/qutebrowser/misc/backendproblem.py b/qutebrowser/misc/backendproblem.py index e18669e6b..80b8a710b 100644 --- a/qutebrowser/misc/backendproblem.py +++ b/qutebrowser/misc/backendproblem.py @@ -185,7 +185,7 @@ def _handle_nouveau_graphics(): return button = _Button("Force software rendering", 'qt.force_software_rendering', - True) + 'chromium') _show_dialog( backend=usertypes.Backend.QtWebEngine, because="you're using Nouveau graphics", @@ -194,9 +194,9 @@ def _handle_nouveau_graphics(): "

This allows you to use the newer QtWebEngine backend (based " "on Chromium) but could have noticeable performance impact " "(depending on your hardware). " - "This sets the qt.force_software_rendering = True option " - "(if you have a config.py file, you'll need to set this " - "manually).

", + "This sets the qt.force_software_rendering = 'chromium' " + "option (if you have a config.py file, you'll need to set " + "this manually).

", buttons=[button], ) diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py index d6b4b1300..95b94fae3 100644 --- a/tests/end2end/test_invocations.py +++ b/tests/end2end/test_invocations.py @@ -375,19 +375,3 @@ def test_qute_settings_persistence(short_tmpdir, request, quteproc_new): quteproc_new.start(args) assert quteproc_new.get_setting('search.ignore_case') == 'always' - - -@pytest.mark.no_xvfb -@pytest.mark.no_ci -@pytest.mark.not_mac -def test_force_software_rendering(request, quteproc_new): - """Make sure we can force software rendering with -s.""" - if not request.config.webengine: - pytest.skip("Only runs with QtWebEngine") - - args = (_base_args(request.config) + - ['--temp-basedir', '-s', 'qt.force_software_rendering', 'true']) - quteproc_new.start(args) - quteproc_new.open_path('chrome://gpu') - message = 'Canvas: Software only, hardware acceleration unavailable' - assert message in quteproc_new.get_content() diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index 5a1fea72c..2e1f6fe1a 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -252,6 +252,19 @@ class TestYaml: data = autoconfig.read() assert data['tabs.favicons.show']['global'] == expected + @pytest.mark.parametrize('force, expected', [ + (True, 'software-opengl'), + (False, 'none'), + ]) + def test_force_software_rendering(self, yaml, autoconfig, force, expected): + autoconfig.write({'qt.force_software_rendering': {'global': force}}) + + yaml.load() + yaml._save() + + data = autoconfig.read() + assert data['qt.force_software_rendering']['global'] == expected + def test_renamed_key_unknown_target(self, monkeypatch, yaml, autoconfig): """A key marked as renamed with invalid name should raise an error.""" diff --git a/tests/unit/config/test_configinit.py b/tests/unit/config/test_configinit.py index 6f3f0e1e5..2bda41182 100644 --- a/tests/unit/config/test_configinit.py +++ b/tests/unit/config/test_configinit.py @@ -288,8 +288,10 @@ class TestEarlyInit: config.instance.set_str('fonts.monospace', 'Terminus') @pytest.mark.parametrize('config_opt, config_val, envvar, expected', [ - ('qt.force_software_rendering', True, + ('qt.force_software_rendering', 'software-opengl', 'QT_XCB_FORCE_SOFTWARE_OPENGL', '1'), + ('qt.force_software_rendering', 'qt-quick', + 'QT_QUICK_BACKEND', 'software'), ('qt.force_platform', 'toaster', 'QT_QPA_PLATFORM', 'toaster'), ('qt.highdpi', True, 'QT_AUTO_SCREEN_SCALE_FACTOR', '1'), ('window.hide_decoration', True, @@ -397,6 +399,14 @@ class TestQtArgs: expected = [sys.argv[0], '--disable-shared-workers'] assert configinit.qt_args(parsed) == expected + def test_disable_gpu(self, config_stub, monkeypatch, parser): + config_stub.val.qt.force_software_rendering = 'chromium' + monkeypatch.setattr(configinit.objects, 'backend', + usertypes.Backend.QtWebEngine) + parsed = parser.parse_args([]) + expected = [sys.argv[0], '--disable-gpu'] + assert configinit.qt_args(parsed) == expected + @pytest.mark.parametrize('arg, confval, used', [ # overridden by commandline arg