[plt-scheme] FrTime implementation

From: Gregory Cooper (greg at cs.brown.edu)
Date: Sat Jan 12 10:15:44 EST 2008

Hi Dave,

Sorry.  I forgot that do-in-manager-after already waits for FrTime to
finish processing, so the channels are unnecessary (and will cause a
deadlock).  The loop code can just read:

(let loop ()
 ;; emit the next pulse
 (send-event fluxus-pulse #t)
 ;; wait for frtime to finish updating everything
 (do-in-manager-after (void))
 ;; draw the frame from a consistent state
 (draw-a-frame <reactive scene description data structure>)
 (loop))

Greg

On Jan 12, 2008 9:31 AM, Dave Griffiths <dave at pawfal.org> wrote:
> Hi Greg,
>
> I've had a go at implementing this, and it seems to hang inside
> (do-in-manager-after (channel-put frtime-chan #t))
> Presumably because the channel-put is being run straight away and
> blocking rather than being deferred... I looked at the macro but got a
> bit lost :)
>
> My code is still very trivial (mostly copy pasted from your email):
>
> (module frtest mzscheme
>
>   (require
>    (lib "lang-ext.ss" "frtime")
>    (all-except (lib "frp-core.ss" "frtime") undefined?))
>
>   (provide
>    set-scene
>    clock)
>
>   (define frtime-chan (make-channel))
>   (define fluxus-pulse (event-receiver))
>   (define scene-list '())
>
>   (define (set-scene s)
>     (set! scene-list s))
>
>   (define clock
>     (hold
>      (map-e
>       (lambda (e)
>         (current-milliseconds))
>       fluxus-pulse)))
>
>   (define (draw-a-frame lst)
>     (for-each
>      (lambda (b)
>        (display (value-now b))(newline))
>      lst))
>
>   (define (loop)
>     ;; emit the next pulse
>     (send-event fluxus-pulse #t)
>     ;; have frtime send a message when it's done updating everything
>     (do-in-manager-after (channel-put frtime-chan #t))
>     ;; wait for the message from frtime
>     (channel-get frtime-chan)
>     ;; draw the frame from a consistent state
>     (draw-a-frame scene-list)
>     (loop))
>
>   (thread (loop))
>
>   )
>
> (require frtest)
>
> (set-scene (list clock))
>
>
>
> On Sun, 2007-12-09 at 06:43 -0500, Gregory Cooper wrote:
> > Ah.  Now I think I understand the problem a bit better.  It sounds
> > like what you'll want is a mechanism for synchronizing FrTime and the
> > Fluxus render loop.  Here's how I'd recommend doing it:
> >
> > 1.  Define an event stream called something like fluxus-pulse:
> >
> >   (define fluxus-pulse (event-receiver))
> >
> > 2.  Define your own versions of the primitive input behaviors you
> > need, which only update on these pulses.  E.g.:
> >
> >   (define clock (hold (map-e (lambda (e) (current-milliseconds)) fluxus-pulse)))
> >
> > 3.  Each time through the render loop, emit a pulse, then wait for
> > FrTime to stabilize, and finally draw.  Here's a rough sketch:
> >
> > (define frtime-chan (make-channel))
> >
> > (let loop ()
> >   ;; emit the next pulse
> >   (send-event fluxus-pulse #t)
> >   ;; have frtime send a message when it's done updating everything
> >   (do-in-manager-after (channel-put frtime-chan #t))
> >   ;; wait for the message from frtime
> >   (channel-get frtime-chan)
> >   ;; draw the frame from a consistent state
> >   (draw-a-frame <reactive scene description data structure>)
> >   (loop))
> >
> > 4.  Note that with this approach, there is no lifting at all
> > (regardless of DrScheme version).  Instead, as you traverse the
> > reactive structure, you'll just test whether each value you encounter
> > is a behavior, and if so, you'll call "value-now" on it before
> > proceeding.
> >
> > Let me know whether this helps or not.
> >
> > Cheers,
> > Greg
> >
> > On Dec 9, 2007 5:57 AM, Dave Griffiths <dave at pawfal.org> wrote:
> > >
> > > On Sat, 2007-12-08 at 22:52 -0500, Gregory Cooper wrote:
> > > > Hi Dave,
> > > >
> > > > It looks like you have the right idea.  :-)
> > > >
> > > > Are you running a pre-v371 version of DrScheme / FrTime?  (From the
> > > > code and description you give, it sounds like you are...)  I ask
> > > > because around July I changed the way FrTime deals with lists and
> > > > other data structures, and this change makes it a bit more complicated
> > > > to lift over data structures containing behaviors.
> > > >
> > > > In pre-v371, all data constructors (including "cons") are lifted, so
> > > > any reactivity inside a data structure spreads to the structure
> > > > itself.  When you lift a procedure over a reactive structure, the
> > > > procedure gets called repeatedly with snapshots of the structure
> > > > (computed each time anything inside the structure changes).  This is
> > > > why the second (make-torus ...) gets redrawn every millisecond, even
> > > > though it only changes once a second: draw-list processes the entire
> > > > list whenever anything inside it changes.
> > > >
> > > > In v371 and later, data constructors are not lifted, so behaviors can
> > > > hide inside structures.  In order to lift over such structures, you'll
> > > > first need to use "raise-reactivity" to make the reactivity spread to
> > > > the top of the structure, or use "compound-lift" (like the new
> > > > animation.ss does), which lets your procedure find the reactivity
> > > > while traversing the structure.  (This avoids the work of constructing
> > > > a deep snapshot each time something changes.)  If you decide to
> > > > upgrade to v371 at some point, let me know and I'll be happy to help
> > > > explain this.
> > >
> > > That makes sense. I'm running 370 - time to upgrade :)
> > >
> > > > A couple of small comments: I'm surprised that you don't have code to
> > > > clear the buffer before rendering the list of shapes, like
> > > > animation.ss does.
> > >
> > > This is the nub of the problem for me really ;)
> > >
> > > When running in drscheme, the render loop is running in a different
> > > (plt) thread.
> > >
> > > This is due to the way fluxus works - you don't drive the render loop
> > > yourself, but you can optionally hook into it to get a function called
> > > by the engine every frame to animate/update things. (using frtime even
> > > this wont be needed)
> > >
> > > This is a Good Thing - the framerate can be detached from the script
> > > update (you can always interactively move the camera around with the
> > > mouse etc)
> > >
> > > The problem with this naive frtime script is that the primitives strobe
> > > as they are drawing once per millisecond, rather than once per frame.
> > > This is fixed by using retained mode primitives (rather than the
> > > immediate mode (draw-*) ones it uses at the moment), which are
> > > maintained inside the render engine and rendered every frame for you,
> > > optimised for speed. then frtime can just update them whenever it wants
> > > to.
> > >
> > > This has implications to how I implement the frtime interface - I'll
> > > need to do some work to make this stateful (for reasons of speed)
> > > situation appear stateless.
> > >
> > > One option is to require the 'user' to name each object, so the frtime
> > > implementation can infer some historical information - first time it
> > > appears build it, other times update it, when it doesn't appear in the
> > > list delete it.
> > >
> > > How does animation.ss cope with this? If a shape only updates once a
> > > second, how does it get redrawn when other things are updating more
> > > quickly?
> > >
> > > > Also, I'm not sure why you don't just write:
> > > >
> > > >   (define clock milliseconds)
> > >
> > > Ah, I was just playing with changing it, but left it as * 1 :)
> > >
> > > cheers,
> > >
> > > dave
> > >
> > >
>
>


Posted on the users mailing list.