rust-gpu v0.4
Screenshot from Embark's Creative Playground, which uses rust-gpu and raytracing.
Hi there! It's been long overdue, but it's finally here: the fourth release of rust-gpu
! Our project aimed at making Rust a first class language and ecosystem for GPU programming. You can read more about why we at Embark started this project in the original announcement.
With this release, all relevant crates have been published to crates.io. In fact, this has been the case since 0.4.0-alpha.13
, released last August. So you no longer have to refer to our github to pull in rust-gpu
, and can instead directly refer to spirv-std
and spirv-builder
by version! What hasn't changed, though, is that you still need to build your shaders using a specific nightly toolchain of Rust. For rust-gpu 0.4.0
, this will be nightly-2022-10-29
. We do produce a user friendly error message when the toolchain you're building with does not exactly match the version required for rust-gpu
.
It has been a while since we published a proper release, and going forward we'd like to do better. We intend to keep rust-gpu
on the same schedule as the stable Rust release, so you can use your favorite new language features as new stable versions of Rust are being released, by just updating your rust-gpu
version. As of right now, rust-gpu
uses a Rust nightly that is equivalent to Rust 1.66
, and you can expect a new release on or around the 26th of January, 2023, when Rust 1.67
is planned to be released.
A lot has changed since v0.3, too much to summarize in these release notes. However, we have started to track our changes in a changelog and have even retroactively listing all changes since the first release 🙂. We'll try our best to feature some of the hightlights here, but please refer to the changelog for a more detailed accounting.
There is one thing we want to highlight in particular: rust-gpu
now supports ray-tracing. Using #[spirv(..)]
attributes, you can define entry points for various raytracing events: intersection
, any_hit
, closest_hit
, and miss
. The #[spirv(ray_generation)]
can be used to define a ray generation shader. We still lack proper examples in our codebase, but for now we can refer you to the spirv_std::ray_tracing
documentation. The code example below shows a somewhat stripped down shader that is used to generate the shadows in above screenshot.
Show ray-tracing code example
pub struct ShadowPayload {
shadowed: u32,
}
pub fn trace_shadow_ray(
acceleration_structure: &AccelerationStructure,
mut ray_desc: RayDesc,
payload: &mut ShadowPayload,
) -> bool {
payload.shadowed = 1;
unsafe {
// see documentation of `spirv_std::ray_tracing::AccelerationStructure` on what these values mean
acceleration_structure.trace_ray(
RayFlags::SKIP_CLOSEST_HIT_SHADER, // ray flags
!0, // cull mask
0, // shader binding table offset
0, // shader binding table stride
0, // miss index
origin, // ray origin
0.0, // tmin
direction, // ray direction
f32::MAX, // tmax
payload, // payload
);
}
payload.shadowed != 0
}
#[spirv(miss)]
pub fn miss(#[spirv(incoming_ray_payload)] payload: &mut ShadowPayload) {
payload.shadowed = 0;
}
#[spirv(ray_generation)]
pub fn raygen(
#[spirv(descriptor_set = 0, binding = 0)] output_tex: &Image!(2D, format=rgba16f, sampled=false),
#[spirv(descriptor_set = 1, binding = 0)] acceleration_structure: &AccelerationStructure,
#[spirv(ray_payload)] payload: &mut ShadowPayload,
) {
let ray_origin = /* calculate ray origin */;
let ray_dir = /* calculate ray dir */;
let shadowed = trace_shadow_ray(
acceleration_structure,
ray_origin,
ray_dir,
payload,
);
unsafe {
output_tex.write(px, if shadowed { Vec3::ZERO } else { Vec3::ONE });
}
}
Language and code generation changes
- Updated toolchain to
nightly-2022-10-29
. - Changed the way the
#[spirv(..)]
attribute works, because of the removal ofregister_attr
support in Rust. You now need thespirv
macro attribute to be globally visible by doing:See also this migration guide for more information. PR#926use spirv_std::spirv;
- Replaced
spirv_std::storage_class
"named pointer types" with#[spirv(...)] &T
entry-point parameters. (PR#443). This means you can now use the following code:#[spirv(fragment)] pub fn main( #[spirv(frag_coord)] in_frag_coord: &Vec4, // instead of: #[spirv(frag_coord)] in_frag_coord: Input<Vec4>, output: &mut Vec4, // instead of: mut output: Output<Vec4>, ) { // ... }
- Added basic support for unsized structs (e.g. ending with a
[T]
field). PR#504 - Removed the need to manually specify the storage class for
Image
/Sampler
/ImageSampler
entry-point parameters. PR#567 - Added support for constant memory (
&'static _
references), within the limits of SPIR-V. PR#586 - Added
#[spirv(subgroup_local_invocation_id)]
. PR#848 - Removed the
fn
/closure#[spirv(unroll_loops)]
attribute. You can use#[spirv(unroll)]
on individual code blocks instead. PR#946 - This release includes an experimental new shader IR framework called
SPIR-🇹
, which will ultimately help us in generating better SPIR-V code. This library is opt-in, see here how to enable it. Again, experimental, use at own risk. PR#940
API changes
spirv-std
- Added a
const
-genericImage
type, andImage!
macro wrapping it. PR#359.#[spirv(fragment)] pub fn main( #[spirv(descriptor_set = 0, binding = 0)] image: &Image!(2D, type=f32, sampled), #[spirv(descriptor_set = 1, binding = 1)] image_array: &Image!(2D, type=f32, arrayed, sampled), #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Image!(cube, type=f32, sampled), #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, output: &mut f32, ) { let v2 = glam::Vec2::new(0.0, 1.0); let v3 = glam::Vec3A::new(0.0, 0.0, 1.0); *output = image.sample_depth_reference(*sampler, v2, 1.0); *output += image_array.sample_depth_reference(*sampler, v3, 1.0); *output += cubemap.sample_depth_reference(*sampler, v3, 1.0); }
- As you might have noticed from above example, cubemaps are now supported as well. PR#521
- Float packing/unpacking operations. PR#709
- Lots of other new APIs
Image:Image::gather
/Image::sample_bias
#704,Image::query_*
#608,Image::read_subpass
#643,Image::sample_by_lod
/Image::sample_by_gradient
#498,Image::fetch
#480
arch:arch::read_clock_khr
#757,arch::{signed,unsigned}_{min,max}
#763,arch::*memory_barrier*
#769,arch::IndexUnchecked
#805,arch::atomic_i_increment
#839,arch::atomic
#877
Misc:ByteAddressableBuffer
#735,SampledImage::sample_by_lod
#755,debug_printf!
#768,RayQuery::confirm_intersection
#822,is_helper_invocation
#612,memory_barrier
/control_barrier
#519
spirv-builder
- You can now have multiple SPIR-V modules, one per entry point. PR#551
SpirvBuilder
now supports the ability to set a Rust "target triple" (e.g."spirv-unknown-vulkan1.1"
for Vulkan1.1
). PR#559- Added the ability to query entry-point names. PR#622
- We now verify the build toolchain with the expected toolchain for
rust-gpu
, by checking the commit hash ofrustc
. It needs to match exactly. PR#919. Can be overridden by defining the environment variableRUSTGPU_SKIP_TOOLCHAIN_CHECK
. PR#935. - You can now customize
rustc
invocation parameters using the environment variablesRUSTGPU_RUSTFLAGS="..."
andRUSTGPU_CODEGEN_ARGS="..."
. See documentation for more information. PR#959
Contributors
Thank you to all the contributors who helped make this release possible! 🎉
@8picoz, @andrusha, @anirudh24seven, @BeastLe9enD, @bjorn3, @bnjbvr, @Cactice, @ColeSeverson, @DeanBDean, @DJMcNab, @dvc94ch, @eddyb, @ElectronicRU, @emilk, @evopen, @expenses, @follower, @fu5ha, @hannes-vernooij, @haraldreingruber-dedalus, @hatoo, @Hentropy, @hrydgard, @Jake-Shadle, @Jasper-Bekkers, @khyperia, @MarijnS95, @molikto, @msiglreith, @oisyn, @PrototypeNM1, @RDambrosio016, @repi, @TrueDoctor, @urholaukkarinen, @vladinator1000, @XAMPPRocky