Repository: psychopy/psychopy

Issue:
Ubuntu20 Dual-Screen / Zaphodhead: pyglet.gl.ContextException: Could not create GL context - workaround available
While writing a PsychoPy script it wasn’t possible to choose our second monitor for stimulus presentation. We ran into the ‘pyglet.gl.ContextException: Could not create GL context’ and unfortunately none of the solutions proposed for earlier reports [1] of similar issues helped.

Our system comprises a stimulus PC with two monitors. These are set up as experimenter and stimulus displays via separate X windows, configured via X11 (we used PsychToolbox XOrgConfCreator). Both monitors are connected to an AMD Radeon 550X GPU in Zaphodhead mode. OS is Ubuntu 20.04.5 LTS.

What solved the problem for us in the end was to create an OpenGL context at the beginning of the script like this:

`import pyglet`
`display = pyglet.canvas.Display(x_screen=1)`
`screen = display.get_default_screen()`
`template = pyglet.gl.Config()`
`config = screen.get_best_config(template)`
`context = config.create_context(None)`
`window = pyglet.window.Window(context=context)`

We are not sure how to proceed to integrate this into PsychoPy, but hope this report is useful to fix the issue directly.
[1] https://github.com/mmatl/pyrender/issues/13


Discussion:

Resolving patch:
diff --git a/psychopy/visual/backends/pygletbackend.py b/psychopy/visual/backends/pygletbackend.py
--- a/psychopy/visual/backends/pygletbackend.py
+++ b/psychopy/visual/backends/pygletbackend.py
@@ -15,6 +15,7 @@
 
 import sys
 import os
+import platform
 import numpy as np
 
 import psychopy
@@ -178,10 +179,14 @@ def __init__(self, win, backendConf=None):
                     'integer greater than two. Disabling.')
                 win.multiSample = False
 
-        if pyglet.version < '1.4':
-            allScrs = _default_display_.get_screens()
+        if platform.system() == 'Linux':
+            display = pyglet.canvas.Display(x_screen=win.screen)
+            allScrs = display.get_screens()
         else:
-            allScrs = _default_display_.get_screens()
+            if pyglet.version < '1.4':
+                allScrs = _default_display_.get_screens()
+            else:
+                allScrs = _default_display_.get_screens()
 
         # Screen (from Exp Settings) is 1-indexed,
         # so the second screen is Screen 1
@@ -194,17 +199,18 @@ def __init__(self, win, backendConf=None):
             if win.autoLog:
                 logging.info('configured pyglet screen %i' % win.screen)
 
-        # options that the user might want
-        config = GL.Config(depth_size=win.depthBits,
-                           double_buffer=True,
-                           sample_buffers=sample_buffers,
-                           samples=aa_samples,
-                           stencil_size=win.stencilBits,
-                           stereo=win.stereo,
-                           vsync=vsync,
-                           red_size=win.bpc[0],
-                           green_size=win.bpc[1],
-                           blue_size=win.bpc[2])
+        # configure the window context
+        config = GL.Config(
+            depth_size=win.depthBits,
+            double_buffer=True,
+            sample_buffers=sample_buffers,
+            samples=aa_samples,
+            stencil_size=win.stencilBits,
+            stereo=win.stereo,
+            vsync=vsync,
+            red_size=win.bpc[0],
+            green_size=win.bpc[1],
+            blue_size=win.bpc[2])
 
         # check if we can have this configuration
         validConfigs = thisScreen.get_matching_configs(config)
@@ -225,24 +231,26 @@ def __init__(self, win, backendConf=None):
             style = None
         else:
             style = 'borderless'
+
+        # create the window
         try:
             self.winHandle = pyglet.window.Window(
-                    width=w, height=h,
-                    caption="PsychoPy",
-                    fullscreen=win._isFullScr,
-                    config=config,
-                    screen=thisScreen,
-                    style=style)
+                width=w, height=h,
+                caption="PsychoPy",
+                fullscreen=win._isFullScr,
+                config=config,
+                screen=thisScreen,
+                style=style)
         except pyglet.gl.ContextException:
             # turn off the shadow window an try again
             pyglet.options['shadow_window'] = False
             self.winHandle = pyglet.window.Window(
-                    width=w, height=h,
-                    caption="PsychoPy",
-                    fullscreen=self._isFullScr,
-                    config=config,
-                    screen=thisScreen,
-                    style=style)
+                width=w, height=h,
+                caption="PsychoPy",
+                fullscreen=self._isFullScr,
+                config=config,
+                screen=thisScreen,
+                style=style)
             logging.warning(
                 "Pyglet shadow_window has been turned off. This is "
                 "only an issue for you if you need multiple "


Test patch: