Pygame Zero programmers are not necessarily responsible or adults. Overall
that idea would break several of our documented principles:

http://pygame-zero.readthedocs.io/en/stable/principles.html

On Mon, 18 Jun 2018, 11:09 Radomir Dopieralski, <pyg...@sheep.art.pl> wrote:

> You can't prevent it, but you can explain in the documentation that it
> is discouraged and what happens when they do it. Python programmers are
> responsible adults after all, no?
>
> Otherwise you start writing Java in Python...
>
> On Mon, 18 Jun 2018 10:24:25 +0100
> Daniel Pope <ma...@mauveweb.co.uk> wrote:
>
> > The drawing thread should handle all blits to the screen as well as
> > flip. But in a framework we cannot prevent users creating surfaces
> > and mutating them in the logic thread.
> >
> > On Mon, 18 Jun 2018, 09:55 Radomir Dopieralski, <pyg...@sheep.art.pl>
> > wrote:
> >
> > > Them again, if you assume that the drawing thread is doing all the
> > > blits, then the situation is reversed — it's the only thread that
> > > needs write access to the surfaces, and everything is good again.
> > > In your scenario, we still get the correct result, because all the
> > > blits are executed by the drawing thread in the same order in which
> > > they were scheduled — including the blits that modify your
> > > temporary surface with the digits. As long as all the modifications
> > > happen either on one side or the other, we are good.
> > >
> > > On Mon, 18 Jun 2018 01:09:16 +0200
> > > Radomir Dopieralski <pyg...@sheep.art.pl> wrote:
> > >
> > > > Oh, I think I misunderstood what the drawing thread was supposed
> > > > to do. I thought it would only handle the "flip" and/or "update"
> > > > calls, that is, sending the pixel data of the screen surface to
> > > > the graphic cards, which is the slowest part of any pygame
> > > > program. But from what you write, I understand it's supposed to
> > > > handle all blits as well?
> > > >
> > > > On Sun, 17 Jun 2018 17:33:54 -0500
> > > > Luke Paireepinart <rabidpoob...@gmail.com> wrote:
> > > >
> > > > > Radomir, there is another side effect - if the surfaces are not
> > > > > copied, then whatever content was in surf a at the moment that
> > > > > it was supposed to be drawn now no longer exists. For example,
> > > > > say the logic thread is font rendering the numbers 1 thru 9,
> > > > > and then blitting these to positions that are not overlapping
> > > > > each other, but it is reusing a surface for the font render
> > > > > call. In the synchronous example, 1, 2, 3, etc would be drawn.
> > > > > Make that asynchronous and you could end up with 9,9,9,9,9....
> > > > >
> > > > > If you are multithreading a game, the "main" thread should be
> > > > > mutating the game state, not the surfaces directly. The render
> > > > > thread should be the view of the model state at the snapshot in
> > > > > time at which the render is called. The logic thread should
> > > > > have a control that is determining the time between updates and
> > > > > applying the appropriate amount of ticks to the game state /
> > > > > emulating physics / etc. Then whenever the previous draw has
> > > > > completed, the render thread would snapshot the state and
> > > > > represent it appropriately (either redrawing or comparing to
> > > > > its previous state). If there needs to be multiple draw calls
> > > > > to represent the state properly since the last state, then they
> > > > > can all be done before the display buffer is flipped.
> > > > >
> > > > > In the 1-9 example, each font would be represented by a game
> > > > > object that had a positional element, and you could add them to
> > > > > the map asynchronous of the draws since the render thread would
> > > > > display them on the next iteration of the render loop where
> > > > > they existed.
> > > > >
> > > > >
> > > > > On Sun, Jun 17, 2018, 3:49 PM Radomir Dopieralski
> > > > > <pyg...@sheep.art.pl> wrote:
> > > > >
> > > > > > Of course strictly speaking there is a difference in behavior,
> > > > > > however, from the practical point of view, the difference
> > > > > > boils down to the fact that something gets drawn half a frame
> > > > > > earlier rather than half a frame later (because the command
> > > > > > to draw it was given in between the frames). Unless you have
> > > > > > less than 6 frames a second, the difference wouldn't be easy
> > > > > > to notice, especially since it would be rather rare too,
> > > > > > since you would need to get very specific timings to even
> > > > > > have it happen. I wonder if it's worth the effort.
> > > > > >
> > > > > > On Sun, 17 Jun 2018 21:40:56 +0100
> > > > > > Daniel Pope <ma...@mauveweb.co.uk> wrote:
> > > > > >
> > > > > > > The mutatation would be on the logic thread side. Consider
> > > > > > > this:
> > > > > > >
> > > > > > > draw_to_screen(surf_a,  ...)
> > > > > > > if cond:
> > > > > > >     surf_a.blit(surf_b, ...)
> > > > > > > draw_to_screen(surf_a, ...)
> > > > > > >
> > > > > > > Currently draw_to_screen() is synchronous. I'd like it to
> > > > > > > queue the blit instead, to happen in another thread. If I
> > > > > > > just did
> > > > > > >
> > > > > > > def draw_to_screen(surf, ...):
> > > > > > >     draw_queue.put((surf, ...))
> > > > > > >
> > > > > > > then there's a race condition - surf_a may be drawn twice
> > > > > > > with the surf_b update.
> > > > > > >
> > > > > > > If draw_to_screen() is implemented like
> > > > > > >
> > > > > > > def draw_to_screen(surf, ...):
> > > > > > >      draw_queue.put((surf.copy(), ...))
> > > > > > >
> > > > > > > Then I get no change in behaviour, but I copy on every
> > > > > > > blit, on the logic thread, ie 2 copies per frame regardless
> > > > > > > of whether cond is True.
> > > > > > >
> > > > > > > Changing the implementation of copy to create a COW clone
> > > > > > > means that the buffer copy actually happens at this line,
> > > > > > > if it is hit:
> > > > > > >
> > > > > > > surf_a.blit(surf_b, ...)
> > > > > > >
> > > > > > > Which means that there's 1 copy if cond is True and 0 if
> > > > > > > cond is False.
> > > > > > >
> > > > > > > On Sun, 17 Jun 2018, 20:59 Radomir Dopieralski,
> > > > > > > <pyg...@sheep.art.pl> wrote:
> > > > > > >
> > > > > > > > On Sun, 17 Jun 2018 17:48:26 +0200
> > > > > > > > Daniel Pope <ma...@mauveweb.co.uk> wrote:
> > > > > > > >
> > > > > > > > > I have been thinking for some time about how to optimise
> > > > > > > > > Pygame Zero games on Raspberry Pi. Most Pi models have
> > > > > > > > > multiple cores and an obvious improvement is to
> > > > > > > > > parallelise. Logic has to be synchronous but I would
> > > > > > > > > like to offload painting the screen to a separate
> > > > > > > > > thread.
> > > > > > > > >
> > > > > > > > > The problem I would have is in passing references to
> > > > > > > > > mutable objects between threads. Primarily this applies
> > > > > > > > > to Surface objects, which are mutable and expensive to
> > > > > > > > > copy. If I have a draw thread that maintains a queue of
> > > > > > > > > screen blit operations, I want the queue to hold
> > > > > > > > > references to surface data that won't change even if I
> > > > > > > > > later mutate the surfaces in the logic thread.
> > > > > > > >
> > > > > > > > Sorry if I am missing something obvious, but it seems to
> > > > > > > > me that the draw thread doesn't need to mutate the
> > > > > > > > surfaces? I mean, it only accesses them in a read-only
> > > > > > > > fashion to render them. So you don't need to pass
> > > > > > > > references to mutable objects — the drawing thread can
> > > > > > > > get a read-only reference. Why do you need it to have a
> > > > > > > > reference to non-changing data? After all, if it changes,
> > > > > > > > you will have to re-draw it in the next frame anyways.
> > > > > > > > Unless the drawing thread is more than one frame behind
> > > > > > > > (which really shouldn't happen), you don't care about the
> > > > > > > > data changing.
>
> --
> Radomir Dopieralski
>

Reply via email to