Skip to content

Commit

Permalink
Merge branch 'main' into rescale
Browse files Browse the repository at this point in the history
  • Loading branch information
cbrnr authored Dec 14, 2024
2 parents 934af16 + 391fd88 commit 99ede2a
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 15 deletions.
1 change: 1 addition & 0 deletions doc/changes/devel/13012.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix errant detection of software-rendered vs hardware-rendered MESA GL contexts in 3D rendering on Linux, by `Eric Larson`_.
14 changes: 14 additions & 0 deletions doc/install/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,20 @@ of VTK and/or QT are incompatible. This series of commands should fix it:
If you installed VTK using ``pip`` rather than ``conda``, substitute the first
line for ``pip uninstall -y vtk``.

3D plotting trouble on Linux
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you are having trouble with 3D plotting on Linux, one possibility is that you
are using Wayland for graphics. To check, you can do:

.. code-block:: console
$ echo $XDG_SESSION_TYPE
wayland
If so, you will need to tell Qt to use X11 instead of Wayland. You can do this
by setting ``export QT_QPA_PLATFORM=xcb`` in your terminal session. To make it
permanent for your logins, you can set it for example in ``~/.profile``.

.. LINKS
Expand Down
22 changes: 22 additions & 0 deletions doc/sphinxext/mne_doc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
import time
import warnings
from pathlib import Path

import numpy as np
import pyvista
Expand All @@ -16,6 +17,7 @@
import mne
from mne.utils import (
_assert_no_instances,
_get_extra_data_path,
sizeof_fmt,
)
from mne.viz import Brain
Expand Down Expand Up @@ -225,6 +227,7 @@ def reset_modules(gallery_conf, fname, when):
mne.viz.ui_events._event_channels
)

orig_when = when
when = f"mne/conf.py:Resetter.__call__:{when}:{fname}"
# Support stuff like
# MNE_SKIP_INSTANCE_ASSERTIONS="Brain,Plotter,BackgroundPlotter,vtkPolyData,_Renderer" make html-memory # noqa: E501
Expand Down Expand Up @@ -262,6 +265,25 @@ def reset_modules(gallery_conf, fname, when):
mem = sizeof_fmt(process.memory_info().rss)
print(f"{prefix}{time.time() - t0:6.1f} s : {mem}".ljust(22))

if fname == "50_configure_mne.py":
# This messes with the config, so let's do so in a temp dir
if orig_when == "before":
fake_home = Path(_get_extra_data_path()) / "temp"
fake_home.mkdir(exist_ok=True, parents=True)
os.environ["_MNE_FAKE_HOME_DIR"] = str(fake_home)
else:
assert orig_when == "after"
to_del = Path(os.environ["_MNE_FAKE_HOME_DIR"])
try:
(to_del / "mne-python.json").unlink()
except Exception:
pass
try:
to_del.rmdir()
except Exception:
pass
del os.environ["_MNE_FAKE_HOME_DIR"]


report_scraper = mne.report._ReportScraper()
mne_qt_browser_scraper = mne.viz._scraper._MNEQtBrowserScraper()
Expand Down
2 changes: 1 addition & 1 deletion examples/preprocessing/otp.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def compute_bias(raw):
idx = epochs.time_as_index(0.036)[0]
data = epochs.get_data(copy=False)[:, :, idx].T
evoked = mne.EvokedArray(data, epochs.info, tmin=0.0)
dip = fit_dipole(evoked, cov, sphere, n_jobs=None, verbose=False)[0]
dip = fit_dipole(evoked, cov, sphere, verbose=False)[0]
actual_pos = mne.dipole.get_phantom_dipoles()[0][dipole_number - 1]
misses = 1000 * np.linalg.norm(dip.pos - actual_pos, axis=-1)
return misses
Expand Down
6 changes: 5 additions & 1 deletion mne/datasets/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,13 @@ def _download_all_example_data(verbose=True):

# If the user has SUBJECTS_DIR, respect it, if not, set it to the EEG one
# (probably on CircleCI, or otherwise advanced user)
fetch_fsaverage(None)
fetch_fsaverage(subjects_dir=None)
logger.info("[done fsaverage]")

# Now also update the sample dataset path, if not already SUBJECTS_DIR
# (some tutorials make use of these files)
fetch_fsaverage(subjects_dir=paths["sample"] / "subjects")

fetch_infant_template("6mo")
logger.info("[done infant_template]")

Expand Down
13 changes: 8 additions & 5 deletions mne/viz/backends/_pyvista.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ def _toggle_antialias(self):
"""Enable it everywhere except on systems with problematic OpenGL."""
# MESA can't seem to handle MSAA and depth peeling simultaneously, see
# https://github.com/pyvista/pyvista/issues/4867
bad_system = _is_mesa(self.plotter)
bad_system = _is_osmesa(self.plotter)
for plotter in self._all_plotters:
if bad_system or not self.antialias:
plotter.disable_anti_aliasing()
Expand Down Expand Up @@ -1319,10 +1319,11 @@ def _disabled_depth_peeling():
depth_peeling["enabled"] = depth_peeling_enabled


def _is_mesa(plotter):
def _is_osmesa(plotter):
# MESA (could use GPUInfo / _get_gpu_info here, but it takes
# > 700 ms to make a new window + report capabilities!)
# CircleCI's is: "Mesa 20.0.8 via llvmpipe (LLVM 10.0.0, 256 bits)"
# and a working Nouveau is: "Mesa 24.2.3-1ubuntu1 via NVE6"
if platform.system() == "Darwin": # segfaults on macOS sometimes
return False
gpu_info_full = plotter.ren_win.ReportCapabilities()
Expand All @@ -1331,8 +1332,9 @@ def _is_mesa(plotter):
gpu_info_full,
)
gpu_info = " ".join(gpu_info).lower()
is_mesa = "mesa" in gpu_info.split()
if is_mesa:
is_osmesa = "mesa" in gpu_info.split()
print(is_osmesa)
if is_osmesa:
# Try to warn if it's ancient
version = re.findall("mesa ([0-9.]+)[ -].*", gpu_info) or re.findall(
"OpenGL version string: .* Mesa ([0-9.]+)\n", gpu_info_full
Expand All @@ -1345,7 +1347,8 @@ def _is_mesa(plotter):
"surface rendering, consider upgrading to 18.3.6 or "
"later."
)
return is_mesa
is_osmesa = "via llvmpipe" in gpu_info
return is_osmesa


class _SafeBackgroundPlotter(BackgroundPlotter):
Expand Down
1 change: 0 additions & 1 deletion mne/viz/backends/_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@
_check_3d_figure, # noqa: F401
_close_3d_figure, # noqa: F401
_close_all, # noqa: F401
_is_mesa, # noqa: F401
_PyVistaRenderer,
_set_3d_title, # noqa: F401
_set_3d_view, # noqa: F401
Expand Down
19 changes: 12 additions & 7 deletions mne/viz/backends/tests/test_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,21 @@ def fail(x):
def test_3d_warning(renderer_pyvistaqt, monkeypatch):
"""Test that warnings are emitted for old Mesa."""
fig = renderer_pyvistaqt.create_3d_figure((800, 600))
_is_mesa = renderer_pyvistaqt.backend._is_mesa
from mne.viz.backends._pyvista import _is_osmesa

plotter = fig.plotter
good = "OpenGL renderer string: OpenGL 3.3 (Core Profile) Mesa 20.0.8 via llvmpipe (LLVM 10.0.0, 256 bits)\n" # noqa
bad = "OpenGL renderer string: OpenGL 3.3 (Core Profile) Mesa 18.3.4 via llvmpipe (LLVM 7.0, 256 bits)\n" # noqa
pre = "OpenGL renderer string: "
good = f"{pre}OpenGL 3.3 (Core Profile) Mesa 20.0.8 via llvmpipe (LLVM 10.0.0, 256 bits)\n" # noqa
bad = f"{pre}OpenGL 3.3 (Core Profile) Mesa 18.3.4 via llvmpipe (LLVM 7.0, 256 bits)\n" # noqa
monkeypatch.setattr(platform, "system", lambda: "Linux") # avoid short-circuit
monkeypatch.setattr(plotter.ren_win, "ReportCapabilities", lambda: good)
assert _is_mesa(plotter)
assert _is_osmesa(plotter)
monkeypatch.setattr(plotter.ren_win, "ReportCapabilities", lambda: bad)
with pytest.warns(RuntimeWarning, match=r"18\.3\.4 is too old"):
assert _is_mesa(plotter)
non = "OpenGL 4.1 Metal - 76.3 via Apple M1 Pro\n"
assert _is_osmesa(plotter)
non = f"{pre}OpenGL 4.1 Metal - 76.3 via Apple M1 Pro\n"
monkeypatch.setattr(plotter.ren_win, "ReportCapabilities", lambda: non)
assert not _is_osmesa(plotter)
non = f"{pre}OpenGL 4.5 (Core Profile) Mesa 24.2.3-1ubuntu1 via NVE6\n"
monkeypatch.setattr(plotter.ren_win, "ReportCapabilities", lambda: non)
assert not _is_mesa(plotter)
assert not _is_osmesa(plotter)

0 comments on commit 99ede2a

Please sign in to comment.