简体   繁体   中英

Python OpenGL - No valid context in thread

I have a window where I want to update the display color (RGB). In order to do so, I'm using Flask (1.1.1) to receive the requests, and PyOpenGL (3.1.0) for the window, using Python 3.7. The system is running on Ubuntu 18.04.

When just running the window, it works and displays the right color. However, as glutMainLoop() is blocking, I want to run it in a thread.

This gives me the following exception:

File "/home/aaa/Desktop/raspberry_pi_display_controller/monitor_manager.py", line 72, in timerFuncWrapper
    self.timerFunc(val)
File "/home/aaa/Desktop/raspberry_pi_display_controller/monitor_manager.py", line 78, in timerFunc
    glutTimerFunc(val, self.timerFuncWrapper, val)
File "/home/aaa/.local/lib/python3.7/site-packages/OpenGL/GLUT/special.py", line 158, in __call__
    callbacks = contextdata.getValue( self.CONTEXT_DATA_KEY )
File "/home/aaa/.local/lib/python3.7/site-packages/OpenGL/contextdata.py", line 104, in getValue
    context = getContext( context )
File "/home/aaa/.local/lib/python3.7/site-packages/OpenGL/contextdata.py", line 41, in getContext
    """Attempt to retrieve context when no valid context"""
OpenGL.error.Error: Attempt to retrieve context when no valid context

As far as I could find online, running OpenGL in a thread works, as long as only one thread at a time operates with OpenGL. I want the main thread to run the Flask server, and this thread dedicated to adjusting the color of the window. How can I implement this?

Here is the code for running in a thread:

from OpenGL.GLUT import *
from OpenGL.GL import *
import sys
from threading import Thread, Event


class MonitorManager(Thread):

    def __init__(self):
        super().__init__()

        self.event = Event()

        self.window_name = "Pi"
        self.red = 1.0
        self.blue = 1.0
        self.green = 1.0
        self.alpha = 1.0

        self.init_glut()

    def init_glut(self):
        glutInit(sys.argv)
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_BORDERLESS | GLUT_CAPTIONLESS)
        glutCreateWindow(self.window_name)
        glutSetCursor(GLUT_CURSOR_NONE)
        glutDisplayFunc(self.displayFuncWrapper)
        glutIdleFunc(self.idleFuncWrapper)
        glutTimerFunc(0, self.timerFuncWrapper, 100)

    def run(self):
        glutMainLoop()

    def displayFuncWrapper(self):
        try:
            self.displayFunc()
        except Exception as e:
            exit(-1)

    def displayFunc(self):
        glClearColor(self.red, self.green, self.blue, self.alpha)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)  # clear the screen to the color of glClearColor
        glutSwapBuffers()
        return

    def idleFuncWrapper(self):
        try:
            self.idleFunc()
        except Exception as e:
            exit(-1)

    def idleFunc(self):
        if self.event.is_set():
            exit(-1)

    def timerFuncWrapper(self, val):
        try:
            self.timerFunc(val)
        except Exception as e:
            exit(-1)

    def timerFunc(self, val):
        self.displayFuncWrapper()
        glutTimerFunc(val, self.timerFuncWrapper, val)

    def update_colors(self, red, green, blue, alpha):
        self.red = red
        self.green = green
        self.blue = blue
        self.alpha = alpha


if __name__ == '__main__':
    a = MonitorManager()
    a.start()

From @Rabbid76's answer, it became apparent that calling glutInit() from the main thread, and all other GLUT function from my thread caused the issue. This SO answer explained that.

To solve my issue, I moved the call to self.init_glut() to run() :

def run(self):
    self.init_glut()
    glutMainLoop()

Now it works like a charm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM