Monday, 4 November 2013

Dynamic Compilation (Part 1)

I already spoke about the fact that I wasn't that keen on Visual graph editor for shaders.

Well I started (thanks to DirectX11.2) to partly change my mind.

In DirectX11.2 they introduced this compiler feature called Function Linking Graph, which basically allows you to link HLSL functions together.

One thing that I quite liked in that in some extent is that the linker is fast (very fast). Another very cool aspect is that you can reflect a function (including parameters). This is really nice, I can have a list of common useful functions (noise/waves...), but also create a function on the fly and have full reflection access.

Having the possibility to get an hybrid approach is a huge step in the right direction, patch only is a bit too monolithic, you end up quickly limited or have to build some pretty heavy patches.

So here is a screenshot of shader patch (builds a pixelshader), It really took very little time to build it:

I have a folder with common functions, which get reflected on load and build node on the fly, but I can as well add my own custom functions on the fly with code editor, that's quite fun ;)

Now there's always a but with these things ;)

First, it only works with Vertex/PixelShaders.

So it's pretty cool to make some nice materials, post processors. I can even make some of my voxel processing with it (trading Compute Shader to few draw calls with GS).

Now one problem besides that, I would love to actually just have the function, and bind it in whatever context I want, this is what I do with subshaders (which are some kind of includes). I have an incomplete shader (that I call host), and bind only the include code. If I simply could include the graph that would be perfect :)

Well it's not possible with linker, but the graph has this quite useful function called : GenerateHLSL :)

So you can get the generated code from it, here is how it looks for the screenshot above:

You have forward function declarations (eg: you still need to add includes yourself), and you have your pixel shader function as inout.

But wait...

Finally let's say I want this prototype:

float GetForce(float3 position);

I can simply tell the pixel shader that i return a float since when you generate hlsl , unlike when you link, you don't care much about context.

So I just need to add a function (to fit the out), or modify my host (with conditional compilation), to change prototype to:

GetForce(float3 position, out float force);

And there we go :)

Of course in that case I just have generated code (eg: no link), so I still have to compile the whole shader, but still, having some graphical tool to build functions opens some new possibilities (sphere tracer, behaviours, colliders)...