Baking Function Pointers

Is there any way to bake function pointers on blobs or entities (or systems?)

I`m creating a system to bake a state machine (as a blob asset) out of a xNode graph but having problems baking user create functions to execute on a specific state.

I have solved baking prefabs as a dynamic buffer element on entity (and index on blob) but for functions there is no way

Associate each function pointer with a type, then bake the stable hash of that type. Then at runtime, load up all associated types and build a hashmap of stable hash to function pointer.

2 Likes

Do you have an example how to associate a function pointer with a type at bake time?

I have types that implement an interface, and I have source generators generate the code that produces the function pointers. Then at startup I find all the types implementing the interface via reflection and get their function pointers.

I see, with source generator it is possible but then it needs assembly reload (sad).

I wish i could change my graphs at runtime and incremental baking changed behaviours, but i think it is not possible

The source generator for me is just to remove a bunch of boilerplate. All it does is set up the static Burst-compiled method and the thing that generates the function pointer.

But really, if your graph is composed of nodes, then each node type would have a function pointer. The full list of node types in your project would only change when you make code changes. If all you did was rearrange the nodes or changed parameters, then you could simply rebake that.

This is unfinished as I paused development due to a Burst bug, but may give you some ideas of what this stuff might look like. It is a system that allows “scripts” packed into a DynamicBuffer to implement “interfaces” which can be invoked polymorphically. It is especially optimal for parallelizing sparse execution. lsss-wip/Packages/com.latios.latiosframework/Unika/Utilities/ScriptSerialization.cs at master · Dreaming381/lsss-wip · GitHub

Also I just noticed line 181 is wrong. That’s supposed to be header.header.scriptType. Basically, I have runtime IDs during baking, and runtime IDs at runtime, which can be different. And then I store the mapping of the bake-time IDs to hashes in a blob asset, and then get the new runtime IDs. The runtime IDs can then be used to index function pointer tables, which I build at startup:

3 Likes

It looks great, thank you.

Just one thing i think is not optimal is that you can maybe patch the blob in place at runtime with the FunctionPointer instead of using a hashmap?

That’s probably possible. I certainly have options if this ends up leaving a dent on the profiler. I opted for API ease-of-use in my initial implementation.

Thank you for sharing. I am looking for a way to bake function pointers :blush:

Has that bug been fixed yet?

No. But the error message changed in Burst 1.8.19, and while still incredibly cryptic, I was able to figure out what in particular Burst didn’t like. Turns out that if you have a default interface method that calls into an interface method implemented by a derived interface or struct, Burst forgets the type information of the derived type, causing null reference exceptions. Similarly, Burst will also forget the generic type arguments for a generic interface with a default interface method.

While I had to sacrifice a couple of minor features, I have the system working now in Burst.

1 Like