Zig is getting support for vec2, vec3, vec4 types to the language

Just wanted to share this :star_struck: add vec2, vec3, vec4 types to the language #32032

15 Likes

Marked “urgent” even. I wonder why?

2 Likes

Yeah can’t wait to see how this will pan out :slight_smile:

Urgent just means triage

Would any graphics programmer be willing to go more into detail about what SPIR-V backend + glsl means within the Zig ecosystem. I understand one is an Intermediate Representation and I understand the second is a shader language (?)

Does zig want to allow shader code to be run on GPUs to be entirely written in Zig?

4 Likes

not a graphics programmer, but I’m pretty sure this is one of zig’s ambition, to be usable as a shading language at least there’s an ofmt=spirv option when emiting code.

2 Likes

Targeting SPIR-V would allow (at least a sizable subset of) the same Zig code to be run reasonably parallel on a CPU, or massively parallel on a GPU or NPU.

This would make Zig’s strength in cross-compilation really useful for use cases like simulation, offline graphics, UI rendering, and anything else where you’d normally have to duplicate work just to have it both on the CPU and GPU (communicating data between the two can be expensive and troublesome, and sometimes you want the CPU as a fallback when a GPU isn’t available or suitable).

It also just makes shader code more approachable for people not specialized in graphics programming. Breakpoints / debuggers are platform and vendor-specific (and necessarily different from CPU debuggers), and print statements are essentially unavailable in GPU programming.

5 Likes

Pardon my ignorance but does it mean zig wants to do what cuda does?

This feels like Zig would be getting multiple features doing extremely similar things without a clear distinction between them. The ticket talks about how @Vector is for SIMD, but vec2/3/4 also describes a number of SIMD operations. It also talks about vec types supporting swizzles, but CPU SIMD often has “permutation” instructions which are swizzles so @Vector would probably benefit from a way to describe those.

Now i16 is equivalent to @Int(signed, 16), so maybe vec4 is equivalent to @Vector(4, f32) as a shorthand. That makes sense to me, but a whole new type doesn’t.

it is an accepted proposal to rename @Vector to @Simd which should help. But the line is pretty clear once you know what the types are.

@Simd is an optimisation primitive for when the compiler doesn’t do a good enough job for you. Meaning that when you use it the compiler trusts that you know better, even if it is clearly suboptimal.
As is usually the case if you try to use it in place of mathematical vectors.

The proposed vec types will be mathematical vectors intended specifically for shaders/game dev.

They have very different use cases, if you find the terminology confusing that is the fault of SIMD using maths language inaccurately. Though it is at least better than using “vector” to describe a dynamic, and generic, array as c++/rust/etc have done.

4 Likes

The proposed vec types will be mathematical vectors intended specifically for shaders/game dev.

Tbh the distinction isn’t clear to me either.

I also never understood where the ‘mathematical vector’ angle is coming from, since game-dev/shading-language vectors are SIMD-style vectors - all operators on vec2..4 are component-wise (most notably multiplication is { .x=a.x*b.x, .y=a.y*b.y, .z=a.z*b.z, .w=a.w*b.w }, and special ‘algebraic’ products like cross- or dot-product are implemented as builtin functions in shading languages (in old-school C++ vector libraries the * and % operators were sometimes overridden to mean either cross- or dot-product, but I don’t think that’s still en vogue and I would advice Zig to not go down that road, instead have a @dot(x, y) and @cross(x, y) builtin, and/or stdlib funcs).

2 Likes

Dot product for single inputs don’t really simdify well. The idea of simd is always to work in batches. For example good simd dot product would look something like (which gives you 3 different dot products!):

pub fn dot_batch(x1: @Vector(3, f32), y1: @Vector(3, f32), z1: @Vector(3, f32), x2: @Vector(3, f32), y2: @Vector(3, f32), z2: @Vector(3, f32)) @Vector(3, f32) {
    const x = x1 * x2;
    const y = y1 * y2;
    const z = z1 * z2;
    return x + y + z;
}
2 Likes

I’m also always perplexed by the mathematical vector distinction. It’s just some “list of numbers” and the easiest way to lay them out is just everything one by one, a SIMD-style.

As for multiplication I would go even so far and just disallow the * operator completely because it isn’t well defined. There at least 4 vector products I can think of on the top of my head that are used reasonably often: dot, cross, hadamard/component, and outer. Having the * as a shortcut for one of those just leads to confusion because the one you want the shortcut for very much depends on context.

If we go further to matrices it’s pretty similar. There are a bunch of products mathematicians came up with. But in contrast to vectors when one talks about a matrix product it’s always the same, while things like the hadamard product here are way more niche.

The batching is a good point, but that works just as well with GLSL-style vec2..vec4, the input data just needs to be provided differently (basically “pre-swizzled”), e.g. I do this sort of ‘4-batching’ in this GLSL shader for GPU skinning (note the xxxx, yyyy, zzzz vecs, this is basically doing a ‘manual’ matrix multiplication via 3 dot products).

2 Likes

My point is that if you use SIMD vector to calculate single dot product, you end up with worse code than doing it with scalars. Linear algebra vectors wouldn’t have to force SIMD code generation so it could decide more what kind of code to generate I guess.

3 Likes

Here is writeup about state of zig gpu backend Zig and GPUs.

4 Likes