From the Burrow

Cepl in Time

2014-04-04 18:23:46 +0000

This post is about time and my ongoing experiments of trying to find a way of representing it in cepl. If you aren’t interested in the journey but are interested in the solution then jump down to the ‘So what’s the result?’ section.

###Why Bother?

It would be very valid to raise the fact that for real-time applications there are some very well-know and suitable ways of handling time (e.g. fixed timestep ) so why wouldn’t we use these techniques?

Often when coding interactively you just want to run something in the repl in pure isolation. These kind of experiments can give rise to new techniques and allow you to toy with idea more easily as you don’t have to worry about any other part of your program. Lisp support this style of programming by having axiomatized some of the core concepts of the language[1] and I wanted that for time as well. I didn’t want to have to take some time delta from another part of my program in order to use it in some function or concept I was developing, I want to focus purely on the task at hand.

###What should time look like?

So after I had decided I wanted some kind of primitive for time in cepl I needed to decide what this would look like. As usual I stole from lisp. Cons cells encapsulate the most basic nature of a list: It is some ‘thing’ followed by some other ‘thing’. So what is time?

Well first off I decided not to look at it from a physics point of view, as this would be unnecessarily complicated, and stick to how time seems to be. Well time is continuous, it doesn’t seem to ‘arrive’ in lumps… but computers by their nature are incremental. So if time is flowing and we treat it like a stream of water, we want to capture time in buckets and then use the captured time to drive some function. OK, that’s weird but time-buffers are kind of what fixed-time-steps implement so lets have ‘time-buffers’ as a concept.

Next…where does the time come from? Well in computing we are used to having streams of data coming from some data source so let’s have a time-source. It also makes sense that we might want to speed up and slow down time so let’s have a time-source be able to be based on another time source with a modifier. We could use this to make a time source that is running 10 times slower than real time. Now if we allow passing of time sources to our time buffers we have a side effect free way of implementing slow motion…even if this only temporary it could be useful for observing some effect slowly to see it is behaving correctly.

When we speak about time we often use some condition to qualify when we are talking about. For example:

  • BEFORE tomorrow do x
  • BETWEEN 10am and 2pm do x
  • AFTER 10 minutes from now do x

These predicates should take a time an return t or nil.

The ‘AFTER’ example is interesting as it includes some syntax for talking about time relative to another point in time. So we will need some kind of ‘from-now’ function.

###The weird bit…

OK so this next part of the process was not reasoned about or based on logic. I was writing down the above and trying to work out other time predicates when I heard a voice in my head say ‘LEXICAL TIME’. This was an odd thing to hear as I had no idea what my brain was talking about..so I stopped for a bit the more I thought about it the more I started to like the idea, we have a temporal-function so you define functionality that implicitly understood time.

I thought it could be some macro that wrapped up the elements we had already created and let the user write code knowing that time was being taken care of.

;;this was the first pseudo-code of a temporal-lambda
(tlambda (x) (within 0 5000) (print x))

###The problems

As usual ideas burst into flame on contact with reality. Here are the major points that arose.

####Expiry

The first problem I noticed was in a tlambda that uses the ‘before’ predicate e.g:

(tlambda () ((before (from-now (seconds 10))) (print "hi")))

Notice that after 10 seconds from now this function will never run again. It essentially has expired. Now I could return some kind of value but this sucks as I was these temporal functions to be identical to regular functions. A friend then recommended using conditions, which turned out to be perfect. So we now have an ‘expired’ condition that can be caught by time aware code.

But when we look at this again we notice that really expired isnt limited to time…it is part of a more general set of conditional-functions. Which crudely stated as a macro could be.

(defmacro defcfun (name args condition &body body)
  `(defun ,name args
     (if ,condition
         (progn ,@body)
         (signal-expired))))

So temporal functions are a type of conditional function. I’m not sure how useful this is…but it was interesting to me.

####Composition and Syntax

The next big issue was in composition and what the resulting code looked like. I was starting to get something working with functions and closures but I started running into a problem as I wanted a predicate that returned t once every x seconds/milliseconds.. something like:

(tlambda () ((each (second 2)) (print "hi"))

But what we actually need is to create a closure with a stepper in the closed vars.

(let ((stepper (make-stepper (seconds 2))))
   (tlambda () (when (funcall stepper) (print "Hi")))

Given that tlambdas were meant to implicitly understand time this seemed ugly.

This was compounded by the next problem…

####Time overflow

Let us define an imaginary tlambda with a nice syntax:

(tlambda ()
  (then ((before (from-now (seconds 5))) (print "hi 1"))
        ((before (from-now (seconds 5))) (print "hi 2"))
        ((before (from-now (seconds 5))) (print "hi 3"))))

What this is meant to do is:

  • run the first before clause until it expires and then
  • run the next clause until expires and then
  • run the third clause until it expires and the signal that the whole tlambda has expired.

Now let’s imagine that we create this tlambda but wait 12 seconds before calling it. The first time we call it should now recognize that the first two clauses have already expired and jump straight to 2 seconds into the third clause.

At this point I could not think of a way of doing this that didnt invlove a DSL. This became even more apparent when I thought about optimizing as I can’t inline the stepper closures and inside the tlambda there would be A LOT of signals being fired and caught.

I was quite annoyed that my knowledge of lisp was potentially limiting me here but at least I could have a go at making a macro version which could be more optimized (if perhaps not as functional as I would originally have liked)

####So what’s the result?

Well the result is a very nice DSL which creates lambdas that know time and can mix temporal syntax with default lisp syntax very easily.

Here are a few examples:

;; when you use default lisp code, the result is a regualr lambda
(tlambda () (print "Hi"))

;; inline lambdas are fine too, again this is just a regular
;; lambda
(tlambda ()
  (let ((text "hello"))
    ((lambda (x) (print x)) text)))

;; This function will for the first 10 seconds print "hi jim" each
;; time it is called. After 10 seconds it will print "jim" each
;; time it is called.
;; Temporal forms are conditional, the predicate must be true for
;; the rest of the form to be evaluated. For this reason we borrow
;; the syntax from the cond macro.
;; Also notice that unlike cond every line is evaluated. So the
;; (print "jim") line always works. This also means this function
;; never actually expires. regular lisp forms can be seen as
;; eternal.
(tlambda ()
  ((before (from-now (seconds 10))) (princ "hi "))
  (print "jim"))

;; time syntax must be either at the root of the tlambda or inside
;; one of the special forms defined for time functions.
;; the following is not valid, as the temporal condition form is
;; within a standard lisp form
(tlambda ()
  (print ((before (from-now (seconds 10))) "hi")))

;; tlambda introduces 2 new special forms: then & repeat
;; they each run each containing form until it expires and
;; only then move to the next form. The difference is that
;; once all the forms have expired 'then' will signal it has
;; expired, whereas repeat will start from the first form again
(tlambda () (then ((before (from-now (seconds 10))) (print "hi"))
                  ((once) (print "allo")))

(tlambda () (repeat ((before (from-now (seconds 10))) (print "hi"))
                    ((once) (print "allo")))

;; progn is also modified so that it can contain the temporal
;; condition forms
(tlambda ()
   (progn ((before (from-now (seconds 2))) (print "hi"))))

####Expansion

Here is an example of what is generated by tlambda (I have tidied it up a little and changed gensym names for ease of reading but functionally it is the same):

;; This:
(tlambda ()
  (then ((before (from-now (seconds 3))) (print "hi"))
        ((before (from-now (seconds 4))) (print "bye"))))

;; expands too:
(let ((counter 0)
      (deadline-1 (from-now (seconds 3)))
      (deadline-2 (from-now (seconds 4))))
  (lambda ()
    (if (= counter 2)
        (signal-expired)
        (when (and (< counter 2))
          (if (afterp deadline-1)
              (progn
                (when (= counter 0)
                  (incf counter)
                  (setf deadline-2 (- (from-now (seconds 4))
                                      (- (funcall *default-time-source*)
                                         (afterp deadline-1)))))
                (if (afterp deadline-2)
                    (when (= counter 1) (incf counter))
                    (when (beforep deadline-2) (print "bye"))))
              (when (beforep deadline-1)
                (print "hi")))))))

####What is missing?

  • Tests and Bugfixing: There are still bugs in this and need to squash them
  • Generate cleaner code: Currently it works well but could be nicer for human reading
  • Generate type declarations: For speed optimization

Well that is all for now. Thanks for reading. The interesting thing now will be playing with this and seeing if the abstraction is actually useful!

Ciao

1. The simplest example of this is lists in lisp. Rather than just being given a list type, with it’s implementation hidden away, we get the cons cell. The cons cell is the smallest abstraction of a linked list and with it we can build lists, tree and other graphs and then use the techniques we have for navigating cons cells (car and cdr (and friends)) to managed all of these different data structures. Also see Paul Graham’s ‘The Roots of Lisp’. It’s a short article, but it hows how with 7 basic primitives you can write an interpreter for an entire lisp language.

Varjo Gets Raw Glsl Functions

2014-03-20 20:11:31 +0000

Yesteday I added the ability for varjo to use blocks of raw glsl code which was a feature I have had a couple of requests for.

The raw blocks are presented as functions and you have to specify the arguments and return type using varjo syntax. This allows varjo to perform the type checks that make this raw function safe to use in your shaders.

The body however is a string and as such I am not doing any checks to ensure the code is valid. If you lie to the compiler things will break :)

This is how a function can be created and used in shaders. Notice that like all external functions it will be automatically included if used in any shader.

VARJO> (v-def-raw-glsl-func raw-test ((a v-int) (b v-float))
           v-float
         "return a * b;")

VARJO> (defshader test-shader ()
         (raw-test 1 2.4))
#<VARJO-COMPILE-RESULT {25EA8929}>

VARJO> (glsl-code *)
"#version 330

float raw_test_1v(int a, float b);

float raw_test_1v(int a, float b) {
return a * b;
}

void main() {
raw_test_1v(1,2.4f);
}
"

One thing I would also like to add is some extra syntax to allow calling out to shader functions written in lisp. This should be pretty easy but I have a HUGE list of other things to implement first so that will have to wait for now.

Seeya folks

Back From Antartica

2014-03-18 22:17:32 +0000

Heya folks, I’ve just got back from sailing to Antartica with the JST. This was simply incredible in way I just can’t work out how to put into text yet, but will soon.

Also I have lots of things I want to add,fix & tweak for my lisp projects so watch this space as, work permitting, I should be putting out a fair bit of stuff this year.

Hope you are all well, Ciao

Here is the a quick preview of what we have been up to!

FUCK YEAH

2013-11-12 23:58:00 +0000

#<CODE {100752B7A3}>

Class: #<STANDARD-CLASS CODE>
Group slots by inheritance [ ]
Sort slots alphabetically  [X]

All Slots:
[ ]  CURRENT-LINE = "mix(1.0f,2.0f,0.5f)"
[ ]  INVARIANT    = NIL
[ ]  OUT-VARS     = NIL
[ ]  RETURNS      = NIL
[ ]  TO-BLOCK     = NIL
[ ]  TO-TOP       = NIL
[ ]  TYPE         = #<V-FLOAT {100751FFE3}>

[set value]  [make unbound]

slime-inspector never looked so good!

Getting Close

2013-11-12 22:27:00 +0000

Been a crazy week of headbuttng a macbookpro until a cocoa application worked followed by a fantastic demoparty (thanks everyone at kindergarten for a phenominal weekend!).

I’m finally back in lisp code (phew!) and I’m around 2/3rds of the way through a rewrite of the Varjo lisp->glsl compiler.

The reason for the rewrite now is that someone asked for a tour through the code explaining how it worked…after 5 minutes of reading I decided it could only be dark-magic holding it together so I have tried to rewrite it to take into account a few of the things I’ve learnt.

Given that I wrote it when I really didnt know anything about glsl I had a lot to change! I have also taken a few of the additions from cepl I had been hacking on and made them core features of the compiler. The big one in this category is you can define shader functions that are only included in the glsl source if they are used. This means you can make a nice ‘standard library’ of functions for your shaders and know they won’t be included unless they are used in a given shader.

There are also macros (regular for now much compiler soon) and generic functions.

I’m hopefully finishing the last of the argument validating this evening and then I think the last big things are reimplementing the special functions and rewriting the string generation. Hopefully I will be done in a week or two.

Right, enough procrastinating, back to work!

CEPL meets SDL2

2013-10-26 12:58:00 +0000

Hey folks, Another cool week or so as cepl appeared in the lisp subreddit and the videos got 980 views in one day, which for me was pretty exciting!

One of the things that came up very quickly was some issues on osx which I originally thought was down to immutable textures. So I added mutable texture storage and the problem still persisted.

Thanks to the fantastic people reporting bugs and in the irc channels I was informed that on some systems when you create a opengl context it picks a lower profile unless you specifically request a higher one. These request functions are only available in sdl2 so I have very hastily ported to sdl2.

This is obviously still a project in the alpha stage of development (is there an earlier term as I’m still working out what this project will be?) so there are plenty of bugs. If you do find them and have a chance please email me or make a bug report in github. This is a part time project but I want to get it in a state suitable for real experimentation with graphics so I will get to the bugs, just slowly sometimes :D

Righto, thanks for stopping by.

Oh almost forgot I have added a very crude compile chaining system so now when you compile a shader stage or sfun it will compile any stage or pipeline that uses it. Woo! I have doen this is a really hacky way but it proves the behaviour is nice so I will build from there.

defsfun

2013-10-19 18:49:00 +0000

One of the recent changes to CEPL has been to add the defsfun macro. This allows defining a shader function that doesnt belong to particular stage, if you use it in a shader it justs gets added to the code.

Here is an example of one:

(defsfun sphere ((p :vec3) (r :float)) 
  (return (- (length (* rot p)) r)))

Now the goal of Varjo was to make shader code look and feel like lisp so the following thought should have been obvious to me from the start but it wasnt. The thought is that if this is so nearly lisp then I could implement lisp versions of a few functions and have a lisp version of a shader that I can run locally for easy testing.

Again, this should have been obvious but I’m quite excited about the posibilities. As I have alreay wrapped the datatypes I can just pass the local version a c-array rather than a gpu array and get it to work.

Obviously the local versions would be too slow to use for rendering but would be great for testing and development in the repl. Also as the shader functions require types w can translate these into declares that will help with the efficiency.

This is a fair way down my list of things to do but after I have nailed time and space abstractions down a bit I will revisit this.

Phew! Lots Happening

2013-10-19 17:27:00 +0000

It has been a crazy few months. I got offered, and accepted, a job at a startup in Norway so about a month back I moved and set up in Oslo.

I’d finally settled in and suddenly CEPL turned up on reddit and people were checking it out, which was great…except I had been making loads of breaking changes in master so it was a bloody mess!

Things are really coming along well though so I need to make some videos showing how the memory handling works. I think I’ll do that tomorrow.

The most recent change I have been making is a rewrite of CEPL’s front-end to the Varjo shader compiler. Previously, when you defined a shader pipeline in CEPL you have to write the shaders inside the defpipeline form. Now they can be defined as separate entities and then the defpipeline stitches them together. Also you can define individual functions outside of the shader stages and they will get mixed in only if they are used in a stage. Along with shader macros I now have some nice tools to experiment with different ways of extending glsl.

I am going to rewrite my ray marcher example to use these features to see what effect it has on the ease of writing and reasoning about the shader pipeline.

Here is a video of the compiler stuff:

Ironman Armor Build

2013-06-08 10:00:05 +0000

This is a photo dump from a build I just completed for a friend. I will be back to add detail to this soon. Ciao!

(+ 'ECL 'QT)

2012-10-28 21:28:41 +0000

EQL!

EQL does look like the absolute answer to my app making prayers. It is a set of ECL bindings for QT which should mean I’m able to both use the power of real-time development, the excellent GUI designing tools of QT and still have small executables thanks to ECL.

The only issue is I can’t install it :b !

Yeah I’m having problems compiling it just now, though I have written to the author to see if he can give any advice. Whatever I find out I will post here.

It is no understatement to say I’m very excited! To be favourable on mobile devices an app really should be as small in size and memory footprint as possible, and this might just let me do both in one fell swoop!

Here’s hoping!

Mastodon