From the Burrow

Flow analyzer complete enough

2015-11-23 10:12:42 +0000

So this week I got the flow analyzer working WOO! There are a few cases it’s missing but the hard stuff (iteration) is done and there’s enough that I can start looking at how to use it

So a refresh:

  • On the cpu side I have a tree of transforms representing different spaces (like a lightweight scenegraph)
  • I want to use these in a sane way on the gpu
  • I cant afford any runtime logic becuase then we are pissing performance up a wall.
  • Matrices describe transforms between spaces. We are interested in the spaces yet we have no explicit way of handling them.
  • If we could use spaces in our shaders and at compile time turn them into matrices (that are then uploaded as uniforms) then things would be much clearer.
  • To be able to resolve this at compile time we need a flow analyzer…which we now have, yay!

So the next question was how to use this.

position is a point (vector) with a space. Position is a compile time construct which will be compiled to a regular vector

space will be the name of the type. Spaces will be passed up as uniforms

(defun-g test ((vert :vec4) &uniform (world space))

I was imagining a transform function that let you transform a position from one space to another:

(transform pos world-space clip-space)

This is kinda dumb though as the position knows what space it is in. So maybe

(transform pos clip-space)

Hmm, might be ok. What would be sweet though is a scope where everything inside is guaranteed to be in a certain space

(in world-space
  (some code)
  (more code))

wait though, this makes transform redundant as

(in clip-space pos)

Would transform the pos to clip-space, and it would return as it’s the last thing in the scope. Sweet!

in is also nicer to write than transform so I think we have a winner.

Note on making positions: in cepl/varjo vectors are made with the v! function. As in (v! 0 1 2) returns a vector3. Position will have a similar interface but it will expect a space, either as an argument or taken from the current in scope. So (p! 0 1 2 world-space) gives you a position3 in world space. (in world-space (p! 0 1 2)) does the same (I may kill the first version so in is the only way to do it)

So assuming this worked how does cepl use it?

My current thinking is that cepl will iterate over the function calls looking for calls involving spaces and positions. It then works out the matrices needed for each calls, de-duplicates the result and adds them as uniforms. Intermediate calculations need to be added to the source code (which I havent worked out the details for yet) and then the new lisp shader code (now without any spaces or positions) is recompiled. The result of this second pass the the shader uploaded to the gpu.

I’m off to america this week so I have no idea if I will get any of this done. We shall see :)

The flow analyzer LIVES (a bit)

2015-11-17 01:38:55 +0000

Had a couple of days off coding but now I’m back. Yet again Ι found limits in the my compiler’s architecture, this time in how I handled environments.

So before what Ι had was roughly as follows:

I have a tree of code that needs compiling. The compiler walks down the tree and compiles each form. The environment is simply an object that holds all the variables and functions that exist at that point in the program. To implement variables scope I simply copy the environment as it was at the start of the scope, add the new variable/s and then throw it away at the end. Because the stuff outside the scope only see’s the original environment it couldnt access variables from the inner scope.

This has worked great for ages but now by flow analyzer wants the answer to the question “what scope was this variable made in?” and that data has been thrown away.

So now I’ve switched to a tree of environments, and they are now all immutable. This was a damn big change so Ι took the opportunity to start using a testing framework so that I could build basic tests while getting everything working again. This went really well so now Ι can show the following.

Let’s take this code. It’s useless but you can see that we make two vectors (that’s the v! forms) each starting with x

(defshader test ()
  (let ((x 1))
    (v! x 0)
      (let ((z 3))
    (v! x 0 0 0)))

Now, if I let the flow analyzer do it’s work and inspect the data for the v! calls, I get something like.

(V! 514 515)
(V! 514 518 519 520)

The numbers are called flow-ids, they are used to track the flow of a value through a program. If two are the same then they are the same value (even if they get bound to different variables or passed through functions).

So above we can see that 514 appears as the id of the first arg for both v! forms, that means it’s not just the same variable (x) but the same value too.

Now in the following example we set x to be a different value (it’s in a progn and a let so I could see if it would track the flow of execution properly).

(defshader test ()
  (let ((x 1))
    (v! x 0)
      (let ((z 3))
        (setq x z)))
    (v! x 0 0 0)))

The flow analysis of the v! calls in this program look like this

(V! 506 507)
(V! 509 510 511 522)

This time the flow-ids of the first argument are different. This shows that, even though they both take x, the system knows the value has been changed.

With these fixes Ι can finally handle conditions as the trees of environments are trivial to diff, so Ι will be able to combine the flow-ids from the two execution paths.

Thanks for reading!

(setf mayhem damnit)

2015-11-10 20:54:27 +0000

When I was making varjo I hacked in support for setf very quickly. It gave the rough feeling of generalized references but even at the time I was thinking that this hack would come back to kick me in the arse..Turns out yesterday it took a run up first..

So I had to take a detour from my detour writing the flow analyzer to rewrite setf. Luckily that wasnt too bad and the code makes way more sense now. So tonight I’m getting back to the flow analyzer and looking at if expressions.

These are a bit fiddly as you (usually) cant tell ahead of time which result is going to be returned. So from the point of the flow analyzer we will say they both do. So if:

(let ((a 2)
      (b 3))
  (if (something-something-stuff)

Then we have to assume both a & b return and continue accordingly.

But wait, what if there are side effects in there?

(let ((c 2))
  (if (something-something-stuff)
      (setf c 10)
      (setf c 20))

Then we have to be aware that the setf is in a condition when we update the flow information.

It’s probably something people who know this kind of thing think is trivial but the way I’ve implemented this so far wasnt done in a way that took this into account. Still exciting though and will be cool when Ι crack it.

Back with more soon

Stumpwm invert colors of one window

2015-11-09 20:47:25 +0000

One of the last things I was missing on my new stumpwm setup was being able to invert the colors of a single window. Turns out this is not hard to do.

  1. Make a script called containing the following

! /bin/bash

if [ "$(pidof compton)" ];
			pkill compton
			xdotool getactivewindow | xargs -I {} compton --backend glx --invert-color-include 'client={}'
  1. chmod +x

  2. Add the following to your .stumpwmrc

    (define-key root-map (kbd “C-i”) “exec /home/baggers/Code/shell/”)

Boom, done. When you click <your-prefix> C-i the currently focused windom will be inverted. Running it again disables the effect.

This is pretty hacky and I’d like to make something more integrated with stumpwm so Ι can have multiple inverted windows at a time. That will be easy enough when it comes to it, but for now this does the job.

nanowrimo & flow analysis

2015-11-09 00:20:13 +0000

So more progress today. It’s too late to explain this well but Ιm gonna try dashing it out anyway.

So rendering involves matrices everywhere, a matrix describes a transform, and we often define spaces in terms of a transform and a parent space. The odd thing however is that the spaces involved arent stored with the transform so the context has to be maintained in the programmers head.

This isnt entirely accurate as on the cpu side we may have a matrix stack or a scene graph that does maintain this. But we dont have that context on the gpu (and dont want pay the overhead of it anyway).

The question of whether this could be done in a nice way was what prompted by blogpost yesterday.

I started by assuming Ι could have spaces on the gpu but that Ι wanted to be able to upload on the transforms that were needed. This meant knowing which ‘spaces’ were used in which functions as (transform space-x space-y vec4) needs a different matrix from (transform space-y space-x vec4). This very quickly made me realize that I need some kind of flow analysis in varjo; I need to know where all the values can flow through the system.

Today I got the basics of this working and am going to finish it off over the next few days. I will then use this as a way to statically check the validity of transforms in shaders, which should make more of the shaders intention more transparent. Finally as these primitives will only exist at compile time, we get no performance cost at runtime (as by then its just matrices) woo!

right time for bed, Seeya


2015-11-09 00:06:19 +0000

This post is more of reminder to myself than anything else. Just now Ι made a little macro that not only emitted regular code (symbols and lists) but also had an instance of a class in there. This caused an error Ι hadnt seen before:

; caught ERROR:
;   don't know how to dump #<FLOW-IDENTIFIER :ids (-2905)> (default MAKE-LOAD-FORM method called).

A quick google found this this the excellent answer by Mario:

The problem you are having is due to the fact your the macro not only
creates code, but that this code has actual live objects embedded into
them in this case. That's the def-collection thing. That is not
necessarily a problem, but in this case it is because sbcl does not know
how to save such an object in a fasl. You can either figure out how to
make an appropriate load form, or do something that avoids the use of
the actual live object.

Intriguing, so ‘load forms’ but be a concept in lisp. Let’s have a look:

CLHS: make-load-form

Cool, so it seems that the mechanism for definign how literals are serialized and deserialized by the compiler (sorry if those terms are inaccurate for this lisp feature) and it also seems this can apply to structures and standard objects if you implement make-load-form:

structure, standard-object: Objects of type structure-object and
standard-object may appear in compiled constants if there is an
appropriate make-load-form method defined for that type.

The file compiler calls make-load-form on any object that is
referenced as a literal object if the object is a generalized instance
of standard-object, structure-object, condition, or any of a (possibly
empty) implementation-dependent set of other classes. The file
compiler only calls make-load-form once for any given object within a
single file.

I still feel amazed at how well common lisp turned out, I get lovely suprises like this all the time as I get deeper into the language.

Anyway I need to read deeper into this, looks like fun

Controlling the compiler is AWESOME

2015-11-07 20:06:42 +0000

I really should have gotten used to this idea, with the amount of macro stuff Ι’ve been doing with lisp, but being able to mess around with compiler is just fun.

In the process of my nanowrimo project on making ‘spaces’ for cepl Ι’ve been looking into how these will be handled on the gpu. I want to be able to reason about these more explicitly than just transforming some vector with some matrix, but at runtime Ι need to keep things as simple and with as little indirection as possible.

Whilst on the cpu side I’m living in a (mostly) dynamically typed language, on the gpu I’m fully static. This opens up some possibilities for using/abusing my type system to check these things for me. I am able to add types that exist purely so the typechecker can validate what I’m doing and that will just compile down to a regular glsl vector4.

So one example I could try is:

(let ((pos (p! some-vec world-space)))
  (transform pos view-space))

Where p! is a function that returns a value with type ‘position-world-space’. I can then use the metadata produced by the compiler to work out what matrices (for the various spaces) need to be uploaded. I can also ensure you don’t do something potentially meaningless (like adding two vectors in different spaces) without first indication that that was what you intended.

(let ((pos-1 (p! some-vec world-space))
      (pos-2 (p! some-vec clip-space)))
  (+ pos-1 pos-2))

This is not very interesting though as it’s not normally the mistake you make. Something more interesting would be when you are in a fragment shader (which is implicitly screen space) and you want to do some post-proc lighting based in clip-space. You could use a simple block like this:

(in-space clip-space
  ..your code..)

And you could be sure that any ‘position’ that was used inside would be transformed to the correct space prior to the calculations being carried out. Any time the spaces match it’s a no-op so no conversion code is emitted.

I’m thinking that a chunk to this can be implemented with the compiler the way it is, but for the bits that can’t it means I have to add and expose some new compiler features, which is cool.

So that’s why I’m excited by compilers today :D

Back to work!

p.s. Of course Ι am missing out a bunch of details especially that at least the names of the spaces would have to be statically defined. But ho hum, it will make sense soon :)

Fantastic series on Clojure persistent datastructure internals

2015-11-07 16:19:59 +0000

I’ve just had the joy of stumbling onto this series by Jean Niklas L’orange about clojure persistent datastructure. I had gained a basic understanding of the theory of these before now but this series of posts break it all down really well, including the optimizations that make this datastructure (more) practical.

Understanding Persistent Vector - Part 1 Understanding Persistent Vector - Part 2 Understanding Persistent Vector - Part 3 Understanding Clojure Transients

Not only is fantastically written but Ι believe you could work through this series and write a decent persistent vector implementation by the end of it.

Top notch!


2015-11-03 21:48:29 +0000

This is just a quick check in to log some progress.

Tonight I’ve been poking around in the current event system, mainly it was cleanup but Ι also added the ability to have weak & strong subscriptions to a event node. The weak ones were neccesary to allow GC to cleanup things that were created at the REPL and are now orphaned. However for well written code that guarentees nodes are unsubscribed, the overhead of weakrefs is undesirable.

Currently nodes can also have two functions applied to them, a filter (which can stop an event propagating) and a body (which is just run with the event as an argument). These were added in a hurry so I need to go back and turn these into something sensible. I guess I will just combine them and have the result of the body be an event or nil, events get propagated, nil doesn’t.

We shall see.

NanoWrimo1 - This month's project

2015-11-02 21:25:04 +0000

Right, in this post I want to go over what I’m going to be making this month, but first a summary of day 0.

Rewriting backscatter in cepl turned out to be a really good way to find bugs in the compiler, it was depressingly good at finding them actually. The changes have made the struct handling in varjo much better and made the function dependency code a lot better in cepl.

Whilst the compiler is now producing good glsl, the pipeline crashes hard as soon as you use it :p. Oddly enough commenting out a couple of the uniforms being passed to the pipeline stops it crashing, so I’m assuming I have either screwed up the uniform uploading, or it didn’t work before in examples like this.

Either way it is not the primary focus for this month so I am forcing myself to leave it as it is for now and concentrate on nanowrimo.

On that note let’s talk about that :)

The project for this month is to add a repl friendly, gc’able, optimizable way of managing hierarchies of transforms in cepl. If this sounds like a scene-graph then that’s no surprise, but I’m consciously trying to avoid putting game objects in the graph directly. By this Ι mean Ι don’t want to have some ‘game-object’ type that you have to subclass and that then goes in the graph.

What I would prefer is some means of defining spaces and then having objects subscribe to them. This decouples objects from the means of organizing them.

In this system it is normally wise to have some kind of caching system. This pays off when there are multiple spaces that share a parent. For example if you are calculating the position of each finger on a hand you dont need to recompute the position of the hand each time. Another property that melds well with this is that in many cases you can compute the transforms lazily. You dont need to calculate a parent transform unless the child needs it (or it is needed itself).

Slam this all together and you get a kind of event system. One that caches the latest event rather than propagating them and can be resolved by pulling.

So far so good, but there is one was case I’m interested in. It may be necessary to walk many of the spaces. To that end it would be good to have a flush event that would push all the pending events through the system.

The finale: Input events are just events which always flush. This means it may be possible to merge these event systems to produce a unified interface. One which would allow subscribing to any event. This is basically some odd rx hybrid (with less state safety). Care will have to be taken around the boundaries between different style nodes but more safe systems can be built on top of this (or it can be ignored and just used to feed some higher level system)

This may end up not working out but it’s the experiment for the month and we shall see how it goes :)

Time to go watch a bunch of talks on streams/frp/etc to steal ideas. Wooo!