Pygame flickers only on second run of program

Question:

I have a simple pygame program that I’ve written that I am running on a raspberry pi CM4 using the raspberry pi lite OS (buster). As such I had to install x manually so that pygame would have something to output to. This was done using the following command:

sudo apt-get install --no-install-recommends xserver-xorg xinit x11-xserver-utils openbox

I start the program at startup by having the following in my .bash_profile:

[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && startx -- -nocursor

As well as this code in /etc/xdg/openbox/autostart:

# Disable any form of screen saver / screen blanking / power management
xset s off
xset s noblank
xset -dpms

# Allow quitting the X server with CTRL-ATL-Backspace
setxkbmap -option terminate:ctrl_alt_bksp

cd project_dir && python project.py

Here’s the contents of project_dir/project.py:

import pygame as pg

class Game:
    def __init__(self):
        pg.init()

        self.__clock = pg.time.Clock()

        self.__window_size = (1024, 768)
        self.__project_size = (392, 291)

        self.screen = pg.display.set_mode(self.__window_size, pg.FULLSCREEN)

        self.blank_background = pg.transform.scale(pg.image.load("assets/default_background.png"),
                self.__window_size).convert()
        self.grid_image = pg.transform.scale(pg.image.load("assets/new_project_thumb.png"),
                self.__project_size).convert()

        self.project_selected = 0

        self.rect_pixels = 3

        self.grid_locations = self.calculate_grid_locations()

    def run(self) -> None:
        pg.mouse.set_visible(False)

        playing = True

        while playing:
            events = pg.event.get()

            button_event = None

            self.screen.blit(self.blank_background, (0, 0))

            for event in events:
                if event.type == pg.KEYDOWN:
                    button_event = event.key

            if button_event == pg.K_LEFT:
                self.project_selected = max((self.project_selected - 1), 0)

            if button_event == pg.K_RIGHT:
                self.project_selected = min((self.project_selected + 1), 3)

            if button_event == pg.K_ESCAPE:
                playing = False

            self.draw_menu()
            pg.display.update()
            self.__clock.tick(6)

    def draw_menu(self):
        for i in range(4):
            if i == self.project_selected:
                rect_loc = (self.grid_locations[i][0] - self.rect_pixels,
                            self.grid_locations[i][1] - self.rect_pixels)
                pg.draw.rect(self.screen,
                             (237, 28, 36),
                             pg.Rect(rect_loc,
                                     (self.__project_size[0] + self.rect_pixels * 2,
                                      self.__project_size[1] + self.rect_pixels * 2)))

            self.screen.blit(self.grid_image, self.grid_locations[i])
                                                        

    def calculate_grid_locations(self):
        w=int((self.__window_size[0] - 2 * self.__project_size[0]) / 3)
        h=int((self.__window_size[1] - 2 * self.__project_size[1]) / 3)

        return [(w, h),
                (w * 2 + self.__project_size[0], h),
                (w, h * 2 + self.__project_size[1]),
                (w * 2 + self.__project_size[0], h * 2 + self.__project_size[1])]

if __name__ == "__main__":
    game = Game()
    game.run()

The program works fine on autostart, but if I quit the program and x after auto-startup using ctrl-alt-backspace and then restart it from the command line using python project.py, the display intermittently flickers between frames of the pygame program. This does not occur when running on my ubuntu laptop, just on the CM4.

Does anyone know what might be causing this?

Asked By: ZPears

||

Answers:

Figured it out – the issue was that I was killing x server. Python / pygame can somehow still output to the screen if x server is killed, but the performance is really degraded. If instead of python project.py I run startx -- -nocursor again, it starts x server again and also runs the whole script in /etc/xdg/openbox/autostart as part of that startup, which causes the program to launch as well.

Answered By: ZPears