Skip to content

First class swizzles #519

@voidentente

Description

@voidentente

What makes shading languages stand out is that they are adapted to their use. Rust wasn't designed to be a shading language, and this lack of adaptation becomes obvious as friction.

One such example is swizzles. Glam has to resort to very unergonomic methods:

d = d.with_xy(d.yx());

It's not a joy to write this over and over and over. In GLSL, this is so much simpler:

d.xy = d.yx;

But Rust-GPU is in a position where it could add support for first class swizzles.

  • The goal is user ergonomics -> language server support.
  • Adapting rust-analyzer to Rust-GPU is not suitable, so Rust-GPU must adapt to rust-analyzer -> the language specification.
  • This means swizzles would have to be disguised as normal struct fields.
  • On targets other than spirv the user could config out these fields.
  • On spirv, where the Rust-GPU backend would support first-class swizzles, it would mark the swizzle fields, substituting reads from and writes to these fields with the according reads from and writes to the aliased fields.

Concrete changes: The codegen backend must be aware of a new attribute, spirv(swizzles), which structs can be marked with.

Concrete example:

#[cfg_attr(target_arch = "spirv", spirv(swizzles))]
pub struct Vec2 {
    pub x: f32,
    pub y: f32,

    #[cfg(target_arch = "spirv")]
    pub xx: Vec2,
    #[cfg(target_arch = "spirv")]
    pub xy: Vec2,
    #[cfg(target_arch = "spirv")]
    pub yx: Vec2,
    #[cfg(target_arch = "spirv")]
    pub yy: Vec2,
    #[cfg(target_arch = "spirv")]
    pub xxx: Vec3,
    #[cfg(target_arch = "spirv")]
    pub xxy: Vec3,
    
    // etc..
}

Glam's vectors wouldn't profit from this, of course - at least not immediately - since they would need to reflect the support. But it would at minimum let users define their own vectors, and establish the groundwork for first class swizzle support elsewhere.

And regarding borrowing, the simplest solution would be for Rust-GPU to simply interpret it as "copy then borrow".

// This doesn't borrow v.zyx but copies v.zyx and then borrows it:
let zyx_mut = &mut v.zyx;
let xyz_mut = &mut v.xyz;
f(zyx_mut);
f(xyz_mut);
// No rules broken.

Alternatively, if this behavior is too unexpected, Rust-GPU could also lint it or simply forbid it entirely.

Let me know what you think, and how feasible this would be.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions