Skip to content

SIMD Query Interface

Queries expose a set of SIMD operations that allow you to perform bulk mutations of components on all matched entities. Simple writes and arithmetic operations finish at blazing speeds, and are a great complement to your Runners that deal in more complex logic.

fennecs SIMD operations make use of System.Intrinsics, especailly the AVX2, SSE2 and ARM AdvSIMD vector instructions where available.

Stream<>.Blit<C>

a fennec splashes a paintbucket at an entire wall "Imagine getting all your work done at once!"

The most prominent SIMD operation is Blit, which writes the component value to all entities in the Stream's Query. C must be one of the Stream Types. It requires no additional setup and is always safe.

csharp
var myStream = new Query<Velocity, Position>().Stream();

myStream.Blit(default(Position));
myStream.Blit(new Velocity(c, 0, 0));

Blit is incapable of adding new Components, and is also unable to modify Relation Targets. Use the Query CRUD Add... function for that, which internally uses Blit to write the new components.

Neofox: magnify BEHIND THE SCENES

Blit uses Span<T>.Fill to write the data. This is a fast and safe operation that is optimized by the .NET runtime and JIT compiler.

Fast Vectorization techniques are used to write Component Types that are Blittable (e.g. struct with only primitive fields), but practically all Reference types are also supported. (they blit rapidly, but not as fast as the Blittables).


Limitations

🔏 ALIASING

For simplicity's sake, if a world is not in WorldMode.Immediate, i.e. when any WorldLock is active, SIMD operations will throw before executing.

Wait, that's illegal!

The reason is that SIMD Operations can lead to aliasing, where multiple threads write the same memory location, or a source and destination location becomes accessible under multiple "aliases" for reading and writing.

This can happen with:

  • most commonly, JOBS (oh, if it weren't for those darn meddling threads!)
  • certain storage JOINS (when a Stream outputs the same backing type multiple times)

(we hope to lift this restriction in the future, probably with per-query/per-archetype locks!)

But because Jobs execute in non-deterministic order, you will not be able to Blit during a Job/from inside a job for the foreseeable time. But fret not - future versions of fennecs will have an aliasing system to allow for safe writes (especially to other queries/archetypes!)

Future SIMD Operations

MORE COMING SOON - (click to preview)

fennec, translucent and glowy blue

Index (writes a running, contiguous index to the component)

MatrixMul

MulMatrix

VectorAdd, VectorDot, VectorCross, VectorScale, VectorOuter, VectorNormalize

Count

integer Arithmetic (AddI, SubtractI, MultiplyI, DivideI, ShiftLeftI, ShiftRightI, ModuloI)

long Arithmetic (AddL, SubtractL, MultiplyL, DivideL, ShiftLeftL, ShiftRightL, ModuloL)

float Arithmetic (AddF, SubtractF, MultiplyF, DivideF)

double Arithmetic (AddD, SubtractD, MultiplyD, DivideD)

QUAD Neofox: glasses WORD Neofox: glasses QUAD Neofox: glasses NERD Neofox: glasses HACK

Psst... until then, you can implement your own arbitrary SIMD operations as seen in the Stream.Raw Example. And since we like to live fast and foxy, try the new extension types in C# 13 for that!

fennecs is released under the MIT License. Neofox is released under the CC BY-NC-SA 4.0 License.