Refactor expr_pylike_eval to add generic C++ version?

This question is more about policy/guidelines and whether potential PR would be rejected on “not the way it should be done” basis.
I am fairly new to trying to modify blender source (as opposed to creating a Python add-on).

To give a bit of context, I was playing with 2.93 Alpha version and trying out Geometry Nodes.
One thing that struck me as quite cumbersome was math operations required a lot of nodes to phrase.

I started looking at whether it is possible to just have an “expression” in the same form that drivers accept them.

After trying to add a quick and dirty proof of concept, I failed to add something sensible for for parsing “natural” way of writing expression (infix).
I started digging through Blender source code and found expr_pylike_eval which sounds like exactly the parsing I’d like to add support for in Geometry Nodes.

expr_pylike_eval is rather neatly written, the one missing thing is that for Geometry Nodes I’d need to make it templated on the argument type.

I would like to change expr_pylike_eval implementation to C++. The rough sketch I had in mind would be:

  • keep existing C API intact, just call into new generic C++ implementation underneath
  • for C++ expose the generic implementation that can be passed in: type of argument (i.e. double, ReadAttribute), list of built-in functions, function to resolve parameter name indices

This would allow me to re-use parsing and evaluation code in Geometry Nodes. I suspect there might be other places in Blender that could later re-use the same approach to implement handling of standard expression throughout the whole source code.

The true two questions I would have here is:

  • is anyone else doing work on something similar to “expression” in Geometry Nodes? (if yes, I guess there is no point in me trying to do the same work)
  • is there going to be opposition to change implementation from C to C++? (as far as I can see everything in blenlib/intern is implemented in C, not sure if there is a reason for this)

Some discussion on expressions for geometry nodes was here. As far as I know it’s not being worked on right now, but someone from the geometry nodes team could clarify that.
https://developer.blender.org/T85655

Generally speaking it’s fine to move code to C++ for reasons like this.

However, it might be best to always evaluate expressions with doubles anyway? That would be most similar to Python 3 expressions, and most predictable for users I think. We want 1/2 to be 0.5, not 0.

Oh, the scalar operations will all be on double. The main thing about geometry nodes is that operations are done on vectors from what I have seen. “Evaluate” is called once for each geometry node, and each attribute will give you vector of N doubles (where N is number of vertices).

Which is why I wanted to template expr_pylike_eval so that it can be called once for expression, not N times (as I suspect can be quite big for a lot of use cases).

It may indeed be faster to evaluate the expression for N values at the same time. N should not be the number of vertices exactly, since you’d get a lot of cache misses that way when N is large. It should be divided in smaller chunks to avoid that. Maybe even SIMD optimizations are possible in the future, though best not to complicate the code with that now.

If the expression contains the ternary operator it also complicates things, since different vertices need to evaluate different operations then.

We definitely want something like this. I actually spend quite some time on coming up with a solution I’m happy with in my free time already. The code is currently in various branches on Github: https://github.com/JacquesLucke/blender
I worked on this and related topics in the fn-expression, fn-expression-new and the mf-procedure branch.

Personally, I’d like to continue to work on the expression system more publicly once it is a bit higher up on our priority list for geometry nodes (maybe for Blender 3.0?).

Indeed. I benchmarked this a bit some months ago. Got like 10-30% speedup by reducing N so much that the intermediate arrays fit into L3 cache, if I remember correctly.

True as well, I already have a solution for that in mind, that is half implemented in the mf-procedure branch on github: https://github.com/JacquesLucke/blender/tree/mf-procedure.
Obviously, more work is necessary to make this master ready.