[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] This program breaks on my Linux



Hey, I bet you forgot about me! :)

I finally upgraded to Ubuntu 14.04. Alas, this problem did not go away. Since the last message:

- I learned it doesn't matter if FPS is artificially capped; but faster FPS seems to make the problem occur more reliably. This rules out throttled vs. un-throttled.
- I learned it doesn't matter if the window is small or big; but smaller gets faster FPS seems to make the problem occur more reliably. This may rule out total blit calls and total pixels per frame.
- I learned it doesn't matter if the game uses the local display or remote over a SSH tunnel. I think this rules out video drivers.
- incorporated the feedback from DR0ID, to put the exit calls outside the main loop.
- incorporated the feedback from Sam, to use print statements to show exit progress.

The issue seems to be in the shutdown/cleanup code of pygame. Yet, as I indicated before the strange behavior (sudden permanent boost in FPS) is observed well before program exit. Although this is harder to spot in Ubuntu 14.04 because I'm getting near max FPS from the beginning.

The updated program is attached.

Gumm


On Sun, Jun 29, 2014 at 8:26 AM, bw <stabbingfinger@xxxxxxxxx> wrote:
Hi, DR0ID,

While it may not be elegant there is nothing syntactically wrong with what I did in the event loop. :) When the misbehavior is not occurring there is no problem exiting the program as it is designed.

To get to the bottom of this I think someone with the right skills and knowledge would have to dig well beneath the Python code. I lack the requisites, unfortunately.

Gumm


On 6/29/2014 02:10, DR0ID wrote:
On 2014-06-28 19:14, bw wrote:
if e.key == K_ESCAPE:
        print(1)
        pygame.display.get_init()
        print(2)
        pygame.display.get_surface()
        print(3)
        screen.unlock()
        print(4)
        pygame.display.set_mode((16, 64))
        print(5)
        pygame.display.flip()
        print(6)
        pygame.quit()
        print(7)
        sys.exit()
        print(8)

In this sequence it's understood 8 will never be reached. When the program exits normally 7 is printed and the program terminates. When the fps gallops away, indicating the problem has occurred, the last thing printed is always 6 and the program hangs. In all cases the pygame functions return, except for pygame.quit(). When trying other exit routines in lieu of pygame.quit() the exiting statement hangs, I presume because pygame's cleanup is called.

Gumm

On 6/28/2014 05:29, Sam Bull wrote:
On ven, 2014-06-27 at 22:35 -0700, bw wrote:
I attached the small program. I'm curious if anyone can run it and
reproduce the problem. I plan on upgrading Ubuntu soon, when I am ready
to risk it: maybe the problem will go away. I'll post the outcome--but
I've been too busy to risk the upgrade, so don't hold yer breath. =)
No idea what the problem could be. I can't reproduce it, but also not
getting more than 130 FPS on my old laptop. I'm curious as to exactly
when it crashes though, can you add some print statements to find
exactly where it crashes?

    Âif e.key == K_ESCAPE:
      Âprint("Before")
      Âpygame.quit()
      Âprint("After Pygame exit")
      Âquit()
      Âprint("Never reached")
    ÂI'd also experiment with a couple of different exit functions, to see if
that makes any difference. For example, try removing the pygame.quit()
call (Pygame will exit safely with Python anyway, so it's a redundant
call here), and using sys.exit() instead of the builtin.


Hi

Could it be that quitting pygame while processing the event queue (well, the if is in the loop where you process the events) isn't that nice?

Maybe this does not address the actual problem, but might help finding the problem.

I would prefer something like this (using the pygame.quit *after* leaving the while loop):

running = True
while running:
  ...
  for event in pygame.event.get():
    ....
      if event.key == K_ESCAPE:
        running = False

pygame.quit()
sys.exit()


Also I thought (maybe I'm wrong) that pygame.quit() is registered by pygame in the 'atexit' module (so no needed to call separately if quiting the program, of course you need a pygame.quit() if you only want to quit pygame but keep python running).

I hope that helps

~DR0ID



import sys
import time

import pygame
from pygame.locals import *

pygame.init()
resolution = 1024, 768
image_size = 200
# these two lines run better over ssh -X ...
#resolution = 196, 16
#image_size = 8
screen = pygame.display.set_mode(resolution, DOUBLEBUF)
screen_rect = screen.get_rect()
scroll_rect = Rect(screen_rect)
scroll_rect.width *= 5
scroll_rect.height *= 5
clock = pygame.time.Clock()
images = (
    pygame.Surface((image_size, image_size)),
    pygame.Surface((image_size, image_size)),
)
images[0].fill(Color('slategray2'))
images[1].fill(Color('slategray3'))
image_rect = images[0].get_rect()
bg_color = Color('black')
dx = -1
dy = -1
max_fps = 0
high_fps = 0
running = True
while running:
    
    dt = clock.tick(max_fps)
    
    fps = int(round(clock.get_fps()))
    if fps > high_fps:
        high_fps = fps
    meter = 'o' * (fps  / 20)
    pygame.display.set_caption('Fps {2}/{0} {1}'.format(fps, meter, high_fps))
    
    scroll_rect.move_ip(dx, dy)
    if not scroll_rect.contains(screen_rect):
        dx = -dx
        dy = -dy
    
    screen.fill(bg_color)
    line_num = 0
    for y in xrange(scroll_rect.y, scroll_rect.bottom, image_size):
        checker = 0 if line_num % 2 else 1
        line_num += 1
        for x in xrange(scroll_rect.x, scroll_rect.right, image_size):
            image_rect.x = x
            image_rect.y = y
            if screen_rect.colliderect(image_rect):
                screen.blit(images[checker], image_rect)
            checker = 0 if checker == 1 else 1
    pygame.display.flip()

    for e in pygame.event.get():
        if e.type == KEYDOWN:
            print('keydown',pygame.key.name(e.key))
            sys.stdout.flush()
            if e.key == K_ESCAPE:
                running = False


def progress(n):
    print('Exit progress: {0}'.format(n))
    sys.stdout.flush()

progress(1)

pygame.display.get_init()
progress(2)

pygame.display.get_surface()
progress(3)

screen.unlock()
progress(4)

pygame.display.set_mode((16, 64))
progress(5)

pygame.display.flip()
progress(6)

pygame.quit()
progress(7)

sys.exit()
progress(8)