Gfx-rs nuts and bolts

Gfx-rs is a low-level graphics abstraction layer in Rust. This blog supposedly hosts the major milestones, concepts, and recaps of the project.


Release of v0.8

30 Apr 2021

gfx-rs community’s goal is to make graphics programming in Rust easy, fast, and reliable. The main projects are:

  • gfx-rs makes low-level GPU programming portable with low overhead. It’s a single Vulkan-like Rust API with multiple backends that implement it: Direct3D 12/11, Metal, Vulkan, and even OpenGL ES.
  • naga translates the shaders between languages, including WGSL. Also provides validation and processing facilities on the intermediate representation.
  • wgpu-rs is built on top of gfx-rs and gpu-alloc/gpu-descriptor. It provides safety, accessibility, and strong portability of applications.

Following the regular schedule of releasing once in a few month, we just rolled out 0.8 versions across gfx/wgpu projects! See gfx-rs changelist, wgpu changelist, and naga changelist for the details.

tree

Naga-based shader infrastructure has been growing and capturing more ground. It has reached an important point where SPIRV-Cross is not just optional on some platforms, but even not enabled by default. This is now the case for Metal and OpenGL backends. Naga path is easier to integrate, share types with, compile, and it’s much faster to run. Early benchmarks suggest about 2.5x perf improvement over SPIRV-Cross for us.

The work on HLSL and WGSL backends is underway. The former will allow us to deprecate SPIRV-Cross on Direct3D 12/11 and eventually remove this C dependency. The latter will help users port the existing shaders to WGSL.

Another big theme of the release is enhanced wgpu validation. The host API side is mostly covered, with occasional small holes discovered by testing. The shader side is now validating both statements and expressions. Programming shaders with wgpu starts getting closer to Rust than C: most of the time you fight the validator to pass, and then it just works, portably. The error messages are still a bit cryptic though, hopefully we’ll improve it in the next release. Hitting a driver panic/crash becomes rare, and we are working on eliminating these outcomes entirely. In addition, wgpu now knows when to zero-initialize buffers automatically, bringing the strong portability story a bit closer to reality.

We also integrated profiling into wgpu and gfx-backend-metal. The author was receptive to our needs and ideas, and we are very happy with the results so far. Gathering CPU performance profiles from your applications today can’t be any simpler:

profiling

In Naga internals, the main internal improvement was about establishing an association of expressions to statements. It allows backends to know exactly if expression results can be re-used, and when they need to be evaluated. Overall, the boundary between statements and expressions became well defined and easy to understand. We also converged to a model, at high level, where the intermediate representation is compact, but there is a bag of derived information. It is produced by the validator, and is required for backends to function. Finally, entry points are real functions now: they can accept parameters from the previous pipeline stages and return results.

Finally, we added a few experimental graphics features for wgpu on native-only:

  • Buffer descriptor indexing
  • Conservative rasterization

P.S. overall, we are in the middle of a grand project that builds the modern graphics infrastructure in pure Rust, and we appreciate anybody willing to join the fight!