z0w0 / helm

A functionally reactive game engine, with headgear to protect you from the headache of game development provided.
http://helm-engine.org/
MIT License
599 stars 69 forks source link

Only re-render when inputs have changed [$50 awarded] #64

Closed kasbah closed 10 years ago

kasbah commented 10 years ago

Helm does not need to re-render when inputs haven't changed.

See discussion here:https://groups.google.com/forum/#!topic/helm-dev/xZCffo1yboU

--- The **[$50 bounty](https://www.bountysource.com/issues/3988085-only-re-render-when-inputs-have-changed?utm_campaign=plugin&utm_content=tracker%2F290443&utm_medium=issues&utm_source=github)** on this issue has been claimed at [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F290443&utm_medium=issues&utm_source=github).
kasbah commented 10 years ago

This binary fractal tree for instance will use 100% CPU on one core constantly (core2duo 1.8Ghz), even when you don't move the mouse or resize the window: https://gist.github.com/kasbah/b6e638655f18c1e11a2c It even does it when using constant signals: https://gist.github.com/kasbah/d0170cd0d4807d18f2a6

z0w0 commented 10 years ago

Yeah, constant signals will simply be sampled the same as a generated signal, so that definitely won't work.

Like I suggested in the thread, I think a cheap but strong optimisation is to hash the AST and window state and only render if it has changed. I'll investigate whether there's any other algorithms I could apply here too. The most obvious speedup is to nuke the GTK stack and use OpenGL but that's still a long way away.

kvanbere commented 10 years ago

An interesting idea might be to use FRP.Elerea.Param rather than FRP.Elerea.Simple. Briefly reading the documentation, I think this would allow you to write elements that changed to an IORef or something (which you pass as a parameter), which you could then check before you render.

Bonus points for also writing the bounds of the changed areas and performing partial renders.

kasbah commented 10 years ago

I started hacking on this a bit over on my fork. I have lift working with the example but I am stuck on ~~ i.e. <*> i.e. liftN.

Posted a question over on SO.

I did look at FRP.Elerea.Param as well but didn't fully grasp how to make use of it.

Any pointers, comments or questions are appreciated.

kasbah commented 10 years ago

OK, so the problem is solved thanks to Reite. With this new definition of Signal all the types to lift and constant etc line up with their Elm counterparts.

With Signal being an instance of Applicative <~ becomes a synonym of <$> and ~~ of <*>. It seems almost wasteful to define these.

I believe Elerea.Clocked could help with setting the sampling rate more accurately (right now I have a threadDelay only when no updating is necessary--which would mean things like random would drive the network at a stupid speed).

Looking over Elerea.Param again it seems it might be good for passing the engine to the signalgens so that the user doesn't have to pass it. Writing things like Mouse.position engine seemed weird when I came to Helm from Elm.

I was playing around a little with writing a Gtk back-end and if we want to support different back-ends (set by an engine-config paramerter) then you really need the engine info at all signalgens so they know what to do based on whether it is a Gtk or an SDL window.

kvanbere commented 10 years ago

Another interesting idea here is supporting partial renders based on the signals or even "layers" cached on surfaces bound to signal diffs.

kasbah commented 10 years ago

Opened #70 for this. Not sure why Github didn't figure that out.

z0w0 commented 10 years ago

Agreed about getting rid of the Mouse.position engine - it was just an ugly workaround. Didn't realise that the param engine would allow it to work without being passed an engine.

kasbah commented 10 years ago

I am not sure it does. It was just a thought. I will look into it after I am finished with the new push-based signalling.

z0w0 commented 10 years ago

Yeah well we certainly need to work it out in order to do custom engine backends.