diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f5429b399..211371b8f34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Toolchain: `nightly-2026-08-15` (rustc 1.99.0) +We're written a new "Getting started" section for rust-gpu with the new `cargo gpu generate` command to set up a rust-gpu workspace for you. This may be interesting for existing users too for an introduction how we imagine a state-of-the-art rust-gpu setup looks like. + ### 🚨BREAKING🚨️ - [PR#661](https://github.com/Rust-GPU/rust-gpu/pull/661) adds support for glam v0.34 and makes it the default glam version diff --git a/README.md b/README.md index 056561f8a4e..504b3fb5236 100644 --- a/README.md +++ b/README.md @@ -59,16 +59,13 @@ See [the examples](examples/) for full details. ## Getting started -Check out [The `rust-gpu` Dev Guide][gpu-guide] for information on how to get started with using it in your projects. - -Experiment with rust-gpu shaders in-browser at [SHADERed][shadered]. +Check out [our docs][gpu-guide] on how to get started using it in your projects. [gpu-guide]: https://rust-gpu.github.io/rust-gpu/book/ -[shadered]: https://shadered.org/shaders?language=rust&sort=hot ## Getting help -For questions and comments, we use [GitHub discussions](https://github.com/Rust-GPU/rust-gpu/discussions) to keep conversations organized and searchable. This also makes it easy to escalate relevant topics to GitHub issues if needed. We do not have an official chat room. +For questions and comments, we use [GitHub discussions](https://github.com/Rust-GPU/rust-gpu/discussions) to keep conversations organized and searchable. This also makes it easy to escalate relevant topics to GitHub issues if needed. There's also a semi-official [discord](https://discord.gg/mDUDgsbBq6). ## Background @@ -107,15 +104,6 @@ We use this repo as a monorepo for everything related to the project: crates, to Right now because the project is in an early state of development, we might introduce temporary changes as stop-gap measures, or implement features or APIs that might not work exactly in a way we end up liking. Therefore it is expected that some (if not most) of the user facing code will change and evolve over time. At the moment this means that we make no guarantees about backwards compatibility and have no formal deprecation model in place. Effectively meaning that currently we only support building from source with the latest `main` branch in our repository. We appreciate our early adopters and would ask them to evolve their code along with ours. -## Structure - -There are a few different components to this repo: - -- [rfcs](docs/src/rfcs) for in-depth discussion and specs. -- [rustc_codegen_spirv](crates/rustc_codegen_spirv) for the compiler itself. -- [spirv-std](crates/spirv-std) for GPU intrinsics, types, and other library items used by GPU crates. -- [spirv-builder](crates/spirv-builder) for a convenient way of building a GPU crate in a CPU build.rs file. - ## Related Projects Historical and other related projects for compiling Rust code to GPUs. diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 7ae6a80bc89..4f02ec609f1 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,17 +1,17 @@ # Summary - [Introduction](./introduction.md) + - [Generating a project](./getting-started/template.md) + - [Rust-GPU workspace structure](./getting-started/structure.md) + - [Writing shaders](./getting-started/shaders.md) + - [Images](./getting-started/images.md) + - [Compute shaders](./getting-started/compute.md) - [Contributing to Rust-GPU]() - - [Building](./building-rust-gpu.md) - [Testing](./testing.md) - - [Debugging](./tracing) + - [Debugging]() - [Tracing](./tracing.md) - [Minimizing bugs in SPIR-V](./spirv-minimization.md) - ["Codegen args" (flags/options) supported by the Rust-GPU codegen backend](./codegen-args.md) - - [Publishing Rust-GPU on crates.io](./publishing-rust-gpu.md) -- [Platform Support](./platform-support.md) -- [Writing Shader Crates](./writing-shader-crates.md) + - [Inline Assembly](./inline-asm.md) - [Features]() - [Attribute syntax](./attributes.md) - - [Inline Assembly](./inline-asm.md) - - [Image type syntax](./image.md) diff --git a/docs/src/building-rust-gpu.md b/docs/src/building-rust-gpu.md deleted file mode 100644 index 0900a102d8b..00000000000 --- a/docs/src/building-rust-gpu.md +++ /dev/null @@ -1,48 +0,0 @@ -# Building Rust-GPU - -## Getting started -1. Clone the repository. - - ```shell - git clone --recurse-submodules https://github.com/rust-gpu/rust-gpu - ``` - -1. **optional** Install [SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools#downloads) and add it to your `PATH`. You can skip this step if you just want to run examples with the defaults. See [Using installed SPIRV-Tools](#using-installed-spirv-tools) if you decide to go with this option. - -1. Next, look at the [examples] folder. There are two kinds of targets here: [runners] and [shaders]. The projects inside `shaders` are "GPU crates", i.e. ones that will be compiled to one or more SPIR-V modules. The `runner` projects are normal, CPU crates that use some graphics backend (currently, we have a [`wgpu` runner][examples/runners/wgpu], a [Vulkan runner][examples/runners/ash] through `ash`, and a barebones pure software [CPU runner][examples/runners/cpu]) to actually run one of the "GPU crate" shaders. - - Run the example: - - ```shell - cargo run --bin example-runner-wgpu - ``` - - This will build `rustc_codegen_spirv`, the compiler, then use that compiler to build [`sky-shader`](examples/shaders/sky-shader) into a SPIR-V module, then finally, build a `wgpu` sample app (modified from [`wgpu`'s examples](https://github.com/gfx-rs/wgpu-rs/tree/master/examples/hello-triangle)) using the built SPIR-V module to display the shader in a window. - -## Prerequisite linux packages recommended to install before building Rust-GPU - -You may need the development version (i.e. headers/etc. included) of some packages in some distributions to be able to -build the examples - specifically, x11 and libxkbcommon, as well as gcc/clang with c++ support. These packages may be -called (fedora) `libX11-devel`, `libxkbcommon-x11-devel`, and `gcc-c++`, or (ubuntu) `libxkbcommon-x11-dev`, -`libx11-dev`, and `gcc`. - -## Using installed SPIRV-Tools - -By default, all of the crates and examples in this repo will compile the [`spirv-tools-sys`](https://crates.io/crates/spirv-tools-sys) crate, including a lot of C++ code from [SPIRV-Tools](https://github.com/EmbarkStudios/SPIRV-Tools). If you don't want to build the C++ code because you already have [SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools#downloads) installed, or just don't want to spend more time compiling, you can build/run the crate with the `use-installed-tools` feature. - -```shell -cargo run \ - --manifest-path examples/example-runner/Cargo.toml \ - --features use-installed-tools \ - --no-default-features -``` - -You should see `warning: use-installed-tools feature on, skipping compilation of C++ code` during the compilation, but otherwise the build will function just the same as if you compiled the C++ code, with the exception that it will fail if you don't have SPIRV-Tools installed correctly. - -[spirv-builder]: https://rust-gpu.github.io/rust-gpu/api/spirv_builder/index.html -[examples]: https://github.com/rust-gpu/rust-gpu/tree/main/examples -[examples/runners]: https://github.com/rust-gpu/rust-gpu/tree/main/examples/runners -[examples/runners/ash]: https://github.com/rust-gpu/rust-gpu/tree/main/examples/runners/ash -[examples/runners/cpu]: https://github.com/rust-gpu/rust-gpu/tree/main/examples/runners/cpu -[examples/runners/wgpu]: https://github.com/rust-gpu/rust-gpu/tree/main/examples/runners/wgpu -[examples/shaders]: https://github.com/rust-gpu/rust-gpu/tree/main/examples/shaders diff --git a/docs/src/getting-started/compute.md b/docs/src/getting-started/compute.md new file mode 100644 index 00000000000..d006d1a44a8 --- /dev/null +++ b/docs/src/getting-started/compute.md @@ -0,0 +1,67 @@ +# Compute shaders + +Unlike vertex or fragment shaders, compute shaders need to declare the size of their workgroup: + +```rust +#[spirv(compute(threads(8, 8)))] +pub fn main() {} +``` + +This one declares a workgroup of the size `(8, 8, 1)`. Any dimensions not declared default to 1. + +Here's a full example of a compute shader that computes `c = a + b`: + +```rust +#[spirv(compute(threads(32)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] a: &[u32], + #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] b: &[u32], + #[spirv(descriptor_set = 0, binding = 2, storage_buffer)] c: &mut [u32], + #[spirv(global_invocation_id)] global_index: UVec3, +) { + let i = global_index.x as usize; + c[i] = a[i] + b[i]; +} +``` + +> [!CAUTION] +> I want to direct your attention to the `c: &mut [u32]` arg. In Rust, mutable references don't just allow you to mutate the referenced memory, but also gives you *exclusive* access to it. Since this mutable references is *shared* between all the threads, it can't be exclusive. +> +> This is a mistake on rust-gpu's entry point API design, not sure when I'll get around to fix it. + +Here's the most interesting built-ins and intrinsics for compute shaders, put together into a rather silly shader that sum up 128 values. The shared memory is also a mutable reference that is not actually exclusive, like the mutable buffers. + +```rust +// assumption: subgroup size == 32 +#[spirv(compute(threads(128)))] +pub fn sum( + #[spirv(global_invocation_id)] global_invocation_id: UVec3, + #[spirv(local_invocation_id)] local_invocation_id: UVec3, + #[spirv(num_workgroups)] num_workgroups: UVec3, + #[spirv(workgroup_id)] workgroup_id: UVec3, + #[spirv(workgroup)] shared_memory: &mut [f32; 4], + #[spirv(spec_constant(id = 0, default = 42))] spec_constant: u32, + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] values: &[f32], + #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] output: &mut f32, +) { + let value = values[global_invocation_id.x as usize]; + let sum_per_subgroup = spirv_std::arch::subgroup_f_add(value); + + let local_idx = local_invocation_id.x as usize; + if local_idx % 32 == 0 { + shared_memory[local_idx / 32] = sum_per_subgroup; + } + + spirv_std::arch::workgroup_memory_barrier_with_group_sync(); + if local_idx == 0 { + let mut accum = 0.; + for i in 0..4 { + shared_memory[i] += accum; + } + *output = accum; + } +} +``` + +> [!Note] +> You currently can't declare the workgroup size as a specialization constant, open an issue if you need this. diff --git a/docs/src/getting-started/images.md b/docs/src/getting-started/images.md new file mode 100644 index 00000000000..38b69292ae3 --- /dev/null +++ b/docs/src/getting-started/images.md @@ -0,0 +1,45 @@ +# Images + +Common image formats can be found in the [`spirv_std::image`](https://rust-gpu.github.io/rust-gpu/api/spirv_std/image/index.html) module. For example, `Image2d` is a very commonly used type, corresponding to `texture2D` in GLSL, and is likely what you want if you want a regular old sampled texture. Here's an example for sampling a texture, though you'd also find many other functions in the [docs on `Image`](https://docs.rs/spirv-std/latest/spirv_std/image/struct.Image.html): + +```rust,no_run +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2dI, + #[spirv(descriptor_set = 1, binding = 1)] image2d_array: &Image2dArray, + #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Cubemap, + #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, +) { + let v2 = Vec2::new(0.0, 1.0); + let v3 = Vec3::new(0.0, 1.0, 2.0); + let r1: IVec4 = image2d.sample(*sampler, v2); + let r2: Vec4 = image2d_array.sample(*sampler, v3); + let r3: Vec4 = cubemap.sample(*sampler, v3); +} +``` + +Use storage images to write to images: + +```rust +#[spirv(fragment)] +pub fn main(#[spirv(descriptor_set = 0, binding = 0)] storage_image: &StorageImage2d) { + let pixel = UVec2::new(123, 456); + let color = Vec4::new(0.3, 0.4, 0.5, 0.6); + unsafe { + storage_image.write(pixel, color); + } +} +``` + +There are a huge number of combinations of image types in SPIR-V, which are represented by a const +generic type called `spirv_std::image::Image`. Specifying the generic parameters of this +type is incredibly tedious, so we have a wrapper macro `spirv_std::Image!` to write the type +instead. The types you've used above are simply type aliases for the output of that macro: + +```rust,no_run +type Image2d = Image!(2D, type=f32, sampled); +type Image2dArray = crate::Image!(2D, type=f32, sampled, arrayed); +type Cubemap = crate::Image!(cube, type=f32, sampled); +``` + +See the [docs of the `Image!` macro](https://rust-gpu.github.io/rust-gpu/api/spirv_std/image/macro.Image.html) for it's syntax. diff --git a/docs/src/getting-started/shaders.md b/docs/src/getting-started/shaders.md new file mode 100644 index 00000000000..806070f444f --- /dev/null +++ b/docs/src/getting-started/shaders.md @@ -0,0 +1,117 @@ +# Writing shaders + +In this chapter we will have a look how to make your own shaders in rust-gpu. + +This introduction is written based on [our rust-gpu template project](./template.md), we recommend setting it up locally if you want to follow along. + + + +### Your first fragment shader + +If you open up [`/mygraphics-shaders/src/lib.rs`](https://github.com/Rust-GPU/rust-gpu-template/blob/main/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/src/lib.rs), you'll find a function called `main_fs` like this: + +```rust +#[spirv(fragment)] +pub fn main_fs(vtx_color: Vec3, output: &mut Vec4) { + *output = Vec4::from((vtx_color, 1.)); +} +``` + +This is an ordinary rust function with a special macro attached to it, marking it as a fragment shader (sometimes also called pixel shader). In this demo, it is evaluated once for each pixel of our triangle and computes the color that this particular pixel should be. So if we wanted our triangle to be all red, we could change the contents of the function to: + +```rust +*output = Vec4::new(1., 0., 0., 1.); +``` + +Now `cargo run` the project and you should see a red triangle. + +Just setting the triangle to a single color is boring, so let's have a look how to declare inputs and outputs. + + + +### Inputs and Outputs + +The fragment shader above is a great example for the two basic parameters: +* `vtx_color: Vec3` parameters passed **by-value** declare an **input** to the shader. In GLSL: `in vec3 vtx_color;`. +* `output: &mut Vec4`: parameters passed **by-mutable-reference** declare an **output** to the shader. In GLSL: `out vec4 output;`. + +Unlike most other shader languages, inputs and outputs can't just be declared anywhere within our code and includes. Instead, they are passed as parameters to your entry point function, centralizing where they can be declared. + +> [!Note] +> While this design makes it a lot easier to figure out all the things your shader is declaring, we are aware that it makes it difficult to share these declarations across multiple shaders. We hope to rectify these problems in future rust-gpu versions. + + + +### Built-ins and Bindings + +Inputs and outputs are by far not the only declaration, so let's have a look at the vertex shader: + +```rust +#[spirv(vertex)] +pub fn main_vs( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] constants: &ShaderConstants, + #[spirv(vertex_index)] vert_id: i32, + #[spirv(position)] vtx_pos: &mut Vec4, + vtx_color: &mut Vec3, +) { + let time = constants.time * constants.speed + vert_id as f32 * (2. * PI * 120. / 360.); + let position = vec2(f32::sin(time), f32::cos(time)) + constants.offset; + *vtx_pos = Vec4::from((position, 0.0, 1.0)); + + *vtx_color = [vec3(1., 0., 0.), vec3(0., 1., 0.), vec3(0., 0., 1.)][vert_id as usize % 3]; +} +``` + +The vertex shader makes the triangle rotate by computing the vertex positions on the GPU. + +It declares two built-ins that are only available vertex shader: +* `#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] constants: &ShaderConstants` declares a storage buffer on the "slot" at descriptor set 0 and binding 0 in glsl terminology. This translates to bind group 0 and binding 0 in the wgpu API, we'll have more detailed look at buffers in the next section. GLSL: `layout(set = 0, binding = 0) ShaderConstants constants;` +* `#[spirv(vertex_index)] vert_id: i32` is an input built-in that is the index of the vertex. GLSL: `gl_VertexID` +* `#[spirv(position)] vtx_pos: &mut Vec4` is an output built-in to set the position of the vertex for the rasterizer. GLSL: `gl_Position` +* `vtx_color: &mut Vec3` is a standard output that is forwarded to our fragment shader. GLSL: `out vec3 vtx_color` + +> [!Note] +> Unfortunately, the built-ins have magic names. You can look up most of them in [this compiletest](https://github.com/Rust-GPU/rust-gpu/blob/main/tests/compiletests/ui/spirv-attr/all-builtins.rs) and [in the compiler source code here](https://github.com/Rust-GPU/rust-gpu/blob/main/crates/rustc_codegen_spirv/src/symbols.rs#L38). + + + +### Sharing data structures between CPU and shaders + +The vertex shader declares a storage buffer of type `ShaderConstants`, which is defined in the shader crate like this: + +```rust +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +#[repr(C)] +pub struct ShaderConstants { + pub time: f32, + pub speed: f32, + pub offset: Vec2, +} +``` + +It is just an ordinary rust struct that derives [`bytemuck::Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html). Deriving `Pod` allows us to use the bytemuck library to convert our struct into a slice of u8s, write those bytes into a buffer on the GPU, and convert them back to our `ShaderConstants` in our shader. But to implement `Pod` our struct needs to fulfill a complex set of unsafe invariants, which the `Pod` derive macro will check for: +* It must be marked with `#[repr(C)]` so our struct has a consistent layout between our CPU compile and shader compile. +* The type must not have any padding. +* It also needs to derive [`Zeroable`](https://docs.rs/bytemuck/latest/bytemuck/trait.Zeroable.html) +* And all of the above must also hold for any members of the struct. + +> [!Warning] +> rust-gpu does not verify that your declarations actually implement `Pod` + +Since the CPU crate `mygraphics` depends on our GPU crate `mygraphics-shaders`, we can use our `ShaderConstants` type in our CPU code. Here is an example constructing our `ShaderConstants`, converting them to a `&[u8]` and creating a new `wgpu` buffer with them: + +```rust +let shader_constants = ShaderConstants { + time: get_time(), + speed: 0.2, + offset: Vec2::new(0., 0.), +}; +let contents = bytemuck::bytes_of(&shader_constants); +let buffer = device.create_buffer_init(&BufferInitDescriptor { + label: Some("ShaderConstants"), + usage: BufferUsages::STORAGE, + contents, +}); +``` + +You can then create a wgpu bind group / vulkan descriptor set with said buffer and submit some work to the GPU with our shader, not detailed here as we assume you to already be familiar with graphics APIs. diff --git a/docs/src/getting-started/structure.md b/docs/src/getting-started/structure.md new file mode 100644 index 00000000000..b50fcffd360 --- /dev/null +++ b/docs/src/getting-started/structure.md @@ -0,0 +1,145 @@ +# Workspace structure + +In [the previous chapter](./template.md), you've generated a new rust-gpu project. Inspecting the directory structure, you'll find something like this: + +```shell +$ tree +. +β”œβ”€β”€ Cargo.lock +β”œβ”€β”€ Cargo.toml +β”œβ”€β”€ mygraphics +β”‚ β”œβ”€β”€ build.rs +β”‚ β”œβ”€β”€ Cargo.toml +β”‚ └── src +β”‚ β”œβ”€β”€ lib.rs +β”‚ β”œβ”€β”€ main.rs +β”‚ └── wgpu_renderer +β”‚ β”œβ”€β”€ mod.rs +β”‚ β”œβ”€β”€ renderer.rs +β”‚ β”œβ”€β”€ render_pipeline.rs +β”‚ └── swapchain.rs +└── mygraphics-shaders + β”œβ”€β”€ Cargo.toml + └── src + └── lib.rs +``` + +> [!Note] +> This is written against the graphics template with wgpu API and cargo-gpu, though other templates shouldn't differ much. + +The first thing you'll notice that it's not just a single crate, but an entire workspace with multiple crates. Refer to [cargo's documentation on workspaces](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) if you've never worked with one. You can also see the two subdirectories `mygraphics` and `mygraphics-shaders`, which are the two crates in our workspaces. + +## `mygraphics-shaders` crate + +By the `shaders` suffix you can already guess this is the crate the shaders live in. + +Opening it's [`lib.rs`](https://github.com/Rust-GPU/rust-gpu-template/blob/main/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/src/lib.rs), you'll notice the many different `#[spirv(..)]` annotations on functions and function arguments. We'll discuss how shaders are written in the [next chapter](./shaders.md), so ignore all of these for now and focus on the declaration in the very first line: `#![no_std]`. + +This crate is a `no_std` crate, meaning you won't have access to the full standard library, but only a platform-independent subset that's called `core`. Meaning you won't be able to do file IO, send network packages or create threads. On a GPU, you won't have access to these APIs, as the GPU has no operating system to handle these requests for us! You also won't be able to access `alloc`, loosing you the `Vec`, `HashMap` and `String` data structures, since (most) GPU APIs won't offer you a memory allocator either. (Some APIs do give you a built-in memory allocator, like CUDA or HIP, but we're not targeting those.) Feel free to read up on [rust's `no_std` documentation](https://docs.rust-embedded.org/book/intro/no-std.html) for more details. + +The crate also has two dependencies: +* **[`spirv-std`](https://crates.io/crates/spirv-std)** is our standard library for GPU functionality. Here you'll find the `#[spirv(..)]` annotation as well as various intrinsics you can call to invoke special GPU functionality. The version of this crate also determines the version of the rust-gpu compiler that will be used to compile your project. +* **[`glam`](https://crates.io/crates/glam)** is a simple and fast vector library, providing you with types such as `Vec2`, `Vec3`, `Vec4` and many more. It even implements some swizzling with `Vec2::xyxx()` and `Vec2::from((vec2, 0., 1.))`. + +Note that the [dependencies are declared like this](https://github.com/Rust-GPU/rust-gpu-template/blob/main/generated/graphics/wgpu/cargo-gpu/Cargo.toml): +```toml +spirv-std = { version = "0.11" } +glam = { version = "0.34", default-features = false } +``` + +> [!Warning] +> The glam crate must have its default features disabled, since by default, it includes the `std` feature which doesn't work on GPUs. Our `spirv-std` crate will implicitly enable the `std` feature of `glam` if you're on a CPU, and will use the fallback `libm` feature when you're on the GPU. + +Additionally, the version of glam you use must also be compatible with `spirv-std`. We do support a number of older glam versions in case you're using a library that hasn't updated, but you must enable it as a feature. For example, if you want to use `glam` v0.32, replace the above dependencies with this: +```toml +spirv-std = { version = "0.11", default-features = false, features = ["glam_0_32"] } +glam = { version = "0.32", default-features = false } +``` +As of writing this, we support `glam` v0.30 to v0.33, and expect that support to grow. Note that we do not support multiple glam versions in parallel, you must only enable one version. + +## `mygraphics` crate + +The `mygraphics` crate is the main executable you've run when you executed `cargo run`. Here you'll have full access to `std` as you're used to, and the place where you interact with whatever graphics API you've chosen. The example implementation we provide are intentionally kept small, just enough to run the demo. Since this isn't a tutorial on how to use any particular graphics API, please refer to whatever documentation or tutorials exist for the graphics API you want to use. + +## Building the shader + +The same `mygraphics` crate has a build script that turns our Rust shaders into artifacts these graphics APIs can understand. A build script is run before the crate is compiled, allowing you to create arbitrary files and/or Rust source code that your crate may need, see [cargo's documentation on build scripts](https://doc.rust-lang.org/cargo/reference/build-scripts.html) for more detail. + +Dependencies of build scripts are separate from your crate's dependencies, so we need to declare those in the [`mygraphics` crate's `Cargo.toml`](https://github.com/Rust-GPU/rust-gpu-template/blob/main/generated/graphics/wgpu/cargo-gpu/mygraphics/Cargo.toml). `cargo-gpu-install` is a slimmed down version of `cargo-gpu` cli specifically for build scripts, with `anyhow` for error throwing convenience. +```toml +[build-dependencies] +cargo-gpu-install = "0.11" +anyhow = "1.0" +``` + +You'll find the script in [`./mygraphics/build.rs`](https://github.com/Rust-GPU/rust-gpu-template/blob/main/generated/graphics/wgpu/cargo-gpu/mygraphics/build.rs) and is arguably the most complicated part of the setup. If you're setting up a new project and not using a template, I'd recommend copying it and adjusting it as needed. The most important part to adjust is the path to the shader crate you want to build. Easiest is to locate it relative to the crate's directory with [`CARGO_MANIFEST_DIR`](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts). +```rust,ignore +let manifest_dir = env!("CARGO_MANIFEST_DIR"); +let crate_path = [manifest_dir, "..", "mygraphics-shaders"] + .iter() + .copied() + .collect::(); +``` + +The next step is to install the required toolchain and build the rust-gpu codegen backend. Instead of specifying a version to install, you pass in the path to the shader crate. It'll resolve the version to install from the `spirv-std` dependency, since those two versions must always *exactly* match. +```rust,ignore +let install = Install::from_shader_crate(crate_path.clone()) + .within_build_script() + .run()?; +``` + +From the returned `install` object you can create arbitrary many `SpirvBuilder`s and configure them. Note that the target to compile for in this example is `spirv-unknown-vulkan1.3`, we'll talk a bit more about targets below. Feel free to read up on [`SpirvBuilder`](https://docs.rs/spirv-builder/latest/spirv_builder/struct.SpirvBuilder.html)s different configuration properties for what all these toggles actually do. + +> [!Warning] +> Within build scripts you must to enable the `build_script.defaults` property, so cargo knows when to rerun the build script, otherwise you might end up with outdated shader artifacts. + +```rust,ignore +let mut builder = install.to_spirv_builder(crate_path, "spirv-unknown-vulkan1.3"); +builder.build_script.defaults = true; +builder.spirv_metadata = SpirvMetadata::Full; +let compile_result = builder.build()?; +``` + +The builder is also where you add any extensions or capabilities you may want to enable: + +```rust +builder.extensions.push("SPV_KHR_ray_tracing".to_owned()); +builder.capabilities.push(Capability::StorageImageWriteWithoutFormat); +``` + +With the shader artifacts built, we need a way to give that artifact to our binary crate. There's many different approaches, from json metadata to rust codegen, but by far the easiest is to pass the path to the artifact as an enviromnent variable. +```rust,ignore +let spv_path = compile_result.module.unwrap_single(); +println!("cargo::rustc-env=SHADER_SPV_PATH={}", spv_path.display()); +``` + +To include the artifact as a binary blob into your crate, it is as simple as +```rust,ignore +const SHADER_ARTIFACT: &[u8] = include_bytes!(env!("SHADER_SPV_PATH")); +``` + +## Integrating common graphics APIs + +### wgpu + +Recommended target: `spirv-unknown-naga-wgsl` + +This target will produce a `*.wgsl` file containing wgsl source code. Internally, we compile to SPIR-V and then use [wgpu's `naga`](https://github.com/gfx-rs/wgpu/tree/trunk/naga) to transpile it to wgsl. Include the wgsl file like this: +```rust,ignore +const WGSL: &str = include_str!(env!("SHADER_SPV_PATH")); +let module: wgpu::ShaderModule = device.create_shader_module(WGSL); +``` + +### ash / Vulkan + +Recommended target: `spirv-unknown-vulkan1.1` or higher + +This target will produce a `*.spv` file containing SPIR-V binary, with the [`ash`](https://crates.io/crates/ash) crate use it like this: +```rust,ignore +const SPV_BYTES: &[u8] = include_bytes!(env!("SHADER_SPV_PATH")); +let spv: Vec = ash::util::read_spv(&mut std::io::Cursor::new(SPV_BYTES))?; +let module: ash::vk::ShaderModule = device.create_shader_module( + &vk::ShaderModuleCreateInfo::default().code(&spv), + None, +)?; +``` diff --git a/docs/src/getting-started/template.md b/docs/src/getting-started/template.md new file mode 100644 index 00000000000..2ad83825328 --- /dev/null +++ b/docs/src/getting-started/template.md @@ -0,0 +1,45 @@ +# Generating a project + +Here we'll describe how you can use our cmdline utility to generate a rust-gpu project from a template. On the next page we'll inspect its structure, so you can replicate it in any existing project. + +First, install our `cargo gpu` cli, if you haven't already: + +```shell +cargo install cargo-gpu +``` + +Then generate a rust-gpu project with: + +```shell +cargo gpu generate +``` + +(This subcommand is merely a wrapper around [`cargo-generate`](https://crates.io/crates/cargo-generate/) invoked on our [`rust-gpu-template` repository](https://github.com/Rust-GPU/rust-gpu-template). If you don't want to run that command, you can also download any expanded template from [the generated subdirectory](https://github.com/Rust-GPU/rust-gpu-template/tree/main/generated).) + +It will ask you a few questions on what kind of project you want: + +**Which sub-template should be expanded?** + +* **graphics**: renders a colorful triangle with vertex and fragment shaders + +Feel free to PR new templates! + +**Project Name:** + +Type whatever recognizable name you want. + +**What API?** + +* **[wgpu](https://github.com/gfx-rs/wgpu)**: WebGPU with a nice rusty interface +* **[ash](https://github.com/ash-rs/ash)**: lightweight wrapper around Vulkan + +If you're unsure, wgpu is generally easier to use. + +**How to integrate rust-gpu?** + +* **[cargo-gpu](https://github.com/Rust-GPU/cargo-gpu) (recommended)**: It's a rust-gpu installation manager that isolates the specific nightly toolchain that rust-gpu requires, allowing the rest of your project to remain on a stable toolchain (or any other toolchain). Other users don't need the cli installed, it just offers some extra utilities. +* **[spirv-builder](https://github.com/Rust-GPU/rust-gpu/tree/main/crates/spirv-builder)** is the older setup that requires your entire project to be compiled using the specific nightly rust-gpu toolchain. + +You should have a new folder named after the project name. Simply `cd` into it and `cargo run` should get you a rotating triangle! + +It may take a while for `mygraphics(build)` to finish when you run it for the first time. We have to download the specific rust toolchain we need and build the rust-gpu codegen backend that functions with it. These preparations are cached externally in `~/.cache/rust-gpu/`, so even after a `cargo clean` the build should still be significantly faster. diff --git a/docs/src/image.md b/docs/src/image.md deleted file mode 100644 index 7c66f86e1ce..00000000000 --- a/docs/src/image.md +++ /dev/null @@ -1,18 +0,0 @@ -# Image type syntax - -There are a huge number of combinations of image types in SPIR-V. They are represented by a const -generic type called `spirv_std::image::Image`, however, specifying the generic parameters of this -type is incredibly tedious, so a wrapper macro, `spirv_std::Image!` can be used to write the type -instead. - -The specific syntax and meaning of the arguments to the `Image!` macro can be found in -[rustdoc](https://rust-gpu.github.io/rust-gpu/api/spirv_std/macro.Image.html). - -Some type aliases for common image formats can be found in the -[`spirv_std::image`](https://rust-gpu.github.io/rust-gpu/api/spirv_std/image/index.html) -module. For example, `Image2d` is a very commonly used type, corresponding to `texture2D` in GLSL, -and is likely what you want if you want a regular old sampled texture. - -```rust,no_run -type Image2d = Image!(2D, type=f32, sampled); -``` diff --git a/docs/src/introduction.md b/docs/src/introduction.md index cbcabaacf3a..b6464ae7134 100644 --- a/docs/src/introduction.md +++ b/docs/src/introduction.md @@ -3,9 +3,10 @@ Welcome to the Rust-GPU dev guide! This documentation is meant for documenting how to use and develop on Rust-GPU. -If you're looking to get started with writing your own shaders in Rust, -check out the [_"Writing Shader Crates"_](./writing-shader-crates.md) section for -more information on how to get started. - -Alternatively if you're looking to contribute to the `rust-gpu` project, have -a look at [_"Building Rust-GPU"_](./building-rust-gpu.md) section. +> [!Important] +> This introduction assumes a basic understanding of GPU and graphics programming. I highly recommend following a tutorial until you have least a colorful triangle on screen or ran your first few compute shaders. +> +> Some of my recommendations: +> * [learn wgpu](https://sotrh.github.io/learn-wgpu/) teaches you the modern WebGPU API with the [wgpu](https://github.com/gfx-rs/wgpu) crate, but doesn't go much beyond the basics. +> * [learnopengl.com](https://learnopengl.com/) is the best graphics programming guide to this day, but it teaches the older OpenGL API which is not supported by rust-gpu. Still, it is one of the best sources intermediary rendering techniques, which you should be able to transfer to a more modern graphics API, or use [glow](https://crates.io/crates/glow) for Rust OpenGL bindings. +> * [How to Vulkan](https://www.howtovulkan.com/) is a tutorial for modern Vulkan and highly recommended over all older Vulkan tutorials. I would not recommend Vulkan for a beginner, since it's a quite extensive API, but it has the most features, extensions and is the best documented API. Unfortunately, rust-gpu doesn't support Buffer Device Address (BDA) yet, so you'll have to resort to ordinary descriptor sets or arrays of descriptor sets like you'd see for bindless textures. diff --git a/docs/src/platform-support.md b/docs/src/platform-support.md deleted file mode 100644 index fd80e7b91fc..00000000000 --- a/docs/src/platform-support.md +++ /dev/null @@ -1,85 +0,0 @@ -# Platform Support -The `rust-gpu` project currently supports a limited number of platforms and graphics APIs. Right now we're not distributing build artifacts and we're primarily focused on the development of the project, so this is based on the current `main` branch. There are a lot of different configurations and hardware out there to support, this document is intended to document what is currently supported, what we intend to support, and what isn't supported. Over time as the project stabilises and our CI improves, more platforms and APIs will be supported and tested. Currently support for each topic is divided into the following three categories. - -- **Primary β€”** Built and tested on CI. -- **Secondary β€”** Built but *not fully tested* on CI. -- **Tertiary β€”** Present in the codebase but not built or tested. - -## Operating System - -| Operating System | Version | Support | Notes -|-------------------|---------|---------|------- -| Windows | 10+ | Primary | | -| Linux | Ubuntu 18.04+ | Primary | | -| macOS | Catalina (10.15)+ | Secondary | Using [MoltenVK], requires v1.1.2+ -| Android | Tested 10-11 | Secondary | | - -[MoltenVK]: https://github.com/KhronosGroup/MoltenVK - -## Graphics APIs - -| Name | Version | Support | Notes -|-------|---------|---------|------- -| SPIR-V | 1.3+ | Primary | -| Vulkan | 1.1+ | Primary | -| WGPU | 0.6 | Primary | Uses a translation layer to Metal/DX12 -| OpenGL | ??? | Tertiary | - -### SPIR-V Targets - -- `spirv-unknown-spv1.0` -- `spirv-unknown-spv1.1` -- `spirv-unknown-spv1.2` -- `spirv-unknown-spv1.3` -- `spirv-unknown-spv1.4` -- `spirv-unknown-spv1.5` -- `spirv-unknown-spv1.6` - -### Vulkan Targets - -- `spirv-unknown-vulkan1.0` -- `spirv-unknown-vulkan1.1` -- `spirv-unknown-vulkan1.1spv1.4` -- `spirv-unknown-vulkan1.2` -- `spirv-unknown-vulkan1.3` -- `spirv-unknown-vulkan1.4` - -### WebGPU Targets - -- `spirv-unknown-webgpu0` - -### OpenGL Targets - -- `spirv-unknown-opengl4.0` -- `spirv-unknown-opengl4.1` -- `spirv-unknown-opengl4.2` -- `spirv-unknown-opengl4.3` -- `spirv-unknown-opengl4.5` - -### OpenCL Targets - -- `spirv-unknown-opencl1.2` -- `spirv-unknown-opencl1.2embedded` -- `spirv-unknown-opencl2.0` -- `spirv-unknown-opencl2.0embedded` -- `spirv-unknown-opencl2.1` -- `spirv-unknown-opencl2.1embedded` -- `spirv-unknown-opencl2.2` -- `spirv-unknown-opencl2.2embedded` - -## GPU - -Currently we don't have specific generations of GPUs for support, as long they support Vulkan 1.1+ with the latest officially installed drivers it should be able build and run the examples. You can check your Vulkan version using the [`vulkaninfo`] command from the `vulkan-sdk`. - -##### Drivers -- [**AMD**][amd-drivers] -- **Intel:** [Linux][linux-intel], [macOS][macos-intel], [Windows][windows-intel] -- [**Nvidia**][nvidia-drivers] - -[nvidia-drivers]: https://www.nvidia.com/Download/index.aspx?lang=en-us -[amd-drivers]: https://www.amd.com/en/support/kb/faq/gpu-56 -[linux-intel]: https://www.intel.com/content/www/us/en/support/articles/000005520/graphics.html -[macOS-intel]: https://www.intel.com/content/www/us/en/support/articles/000022440/graphics.html -[windows-intel]: https://downloadcenter.intel.com/product/80939/Graphics -[`vulkaninfo`]: https://vulkan.lunarg.com/doc/view/latest/windows/vulkaninfo.html - diff --git a/docs/src/publishing-rust-gpu.md b/docs/src/publishing-rust-gpu.md deleted file mode 100644 index 7116f03abaa..00000000000 --- a/docs/src/publishing-rust-gpu.md +++ /dev/null @@ -1,31 +0,0 @@ -# Publishing rust-gpu on crates.io - -This is a task list for the maintainers of rust-gpu to remember to do when publishing a new version -of rust-gpu (probably not useful for contributors without access to our crates.io account πŸ˜‹) - -The published crates and their relative locations are: - -1. `spirv-std-types` (`crates/spirv-std/shared`) -2. `spirv-std-macros` (`crates/spirv-std/macros`) -3. `spirv-std` (`crates/spirv-std`) -4. `rustc_codegen_spirv-types` (`crates/rustc_codegen_spirv-types`) -5. `rustc_codegen_spirv` (`crates/rustc_codegen_spirv`) -6. `spirv-builder` (`crates/spirv-builder`) - -Publishing the crates in above order prevents dependency issues. -These are the steps: - -1. Bump all the versions to the next one in the workspace's `Cargo.toml`. This project uses workspace - inheritance, so this is the only place you'll find these actual versions. Make sure to pin the - rust-gpu dependencies to their _exact_ versions using the `=`-notation, such as: `=0.4.0`. All crates - are built and published in tandem so you're not expected to be able to mix and match between versions. -2. Add this new version to the table in `crates/spirv-builder/README.md` and make sure the correct - nightly version is listed there as well. -3. Create a PR with that change. Wait for CI and a review, and merge it. -4. Pull the merged `main` branch. -5. Tag `main` with the version: `git tag v0.4.0` -6. Push the tag: `git push origin v0.4.0` -7. Publish the crates: `cd [crate] && cargo publish` in the order of the list above. - The crates.io index might take some seconds to update - causing an error if the crates are published in quick succession. Wait a couple of seconds and try - again πŸ™‚. diff --git a/docs/src/writing-shader-crates.md b/docs/src/writing-shader-crates.md deleted file mode 100644 index 83605773767..00000000000 --- a/docs/src/writing-shader-crates.md +++ /dev/null @@ -1,174 +0,0 @@ -# Writing Shader Crates - -This is section is going to walk you through writing a shader in Rust and -setting up your shader crate. - -Be aware that this project is in a very early phase, please [file an -issue](https://github.com/rust-gpu/rust-gpu/issues) if there's something -not working or unclear. - -## Online - -You can now test out and try building shaders with rust-gpu from the browser! - -- [SHADERed] A shader IDE which has a lite version, which allows you to build - and run shaders on the web. -- [Shader Playground] A playground for building and checking the output of - shader code similar to godbolt or play.rust-lang.org. - -[SHADERed]: https://shadered.org/template -[shader playground]: http://shader-playground.timjones.io/9d744d5893beb6a8f129fda50ad4aeeb - -## Local Setup -There are two main ways to setup your shader project locally. - -1. Using the `spirv-builder` crate. - The `spirv-builder` is a crate designed to automate the process of building - and linking the `rust-gpu` to be able to compile SPIR-V shaders into your - main Rust crate. -2. Using `.cargo/config`. - Alternatively if you're willing to do the setup yourself you can manually set - flags in your cargo configuration to enable you to run `cargo build` in your - shader crate. - -### Using `spirv-builder` -If you're writing a bigger application and you want to integrate SPIR-V shader -crates to display, it's recommended to use `spirv-builder` in a build script. - -1. Copy the [`rust-toolchain.toml`] file to your project. (You must use the same - version of Rust as `rust-gpu`. Ultimately, the build will fail with a nice - error message when you don't use the exact same version) -2. Reference `spirv-builder` in your Cargo.toml: - ```toml - [build-dependencies] - spirv-builder = "0.9" - ``` - All dependent crates are published on [crates.io](https://crates.io). -3. Create a `build.rs` in your project root. - -#### `build.rs` -Paste the following into `build.rs` - -```rust,no_run -use spirv_builder::{MetadataPrintout, SpirvBuilder}; - -fn main() -> Result<(), Box> { - SpirvBuilder::new(shader_crate, target) - .print_metadata(MetadataPrintout::Full) - .build()?; - Ok(()) -} -``` - -Substituting `shader_crate` with a relative path to your shader crate. The values available for the `target` parameter are available -[here](./platform-support.md). For example, if building for vulkan 1.1, use -`"spirv-unknown-vulkan1.1"`. - -The `SpirvBuilder` struct has numerous configuration options available, see -[documentation](https://rust-gpu.github.io/rust-gpu/api/spirv_builder/struct.SpirvBuilder.html). - -#### `main.rs` -The following will directly include the shader module binary into your application. -```rust,no_run -const SHADER: &[u8] = include_bytes!(env!(".spv")); -``` - -> **Note** If your shader name contains hyphens, the name of environment variable will be the name with hyphens changed to underscores. - -Keep in mind that by default, build-dependencies are built in debug mode. This -means that the rust-gpu compiler (`rustc_codegen_spirv`) will be built in debug -mode, and will be *incredibly* slow. You can solve this by placing this bit of -configuration in your workspace `Cargo.toml`: - -```toml -# Compile build-dependencies in release mode with -# the same settings as regular dependencies. -[profile.release.build-override] -opt-level = 3 -codegen-units = 16 -[profile.dev.build-override] -opt-level = 3 -``` - -Keep in mind this will optimize *all* build script dependencies as release, -which may slow down full rebuilds a bit. Please read [this -issue](https://github.com/EmbarkStudios/rust-gpu/issues/448) for more -information, there's a few important caveats to know about this. - -### Using `.cargo/config.toml` - -> **Note** This method will require manually rebuilding `rust-gpu` each - time there has been changes to the repository. - -If you just want to build a shader crate, and don't need to automatically -compile the SPIR-V binary at build time, you can use `.cargo/config.toml` to set the -necessary flags. Before you can do that however you need to do a couple of steps -first to build the compiler backend. - -1. Clone the `rust-gpu` repository -2. `cargo build --release` in `rust-gpu`. - -Now you should have a `librustc_codegen_spirv` dynamic library available in -`target/release`. You'll need to keep this somewhere stable that you can -reference from your shader project. - -Copy the `rust-gpu/rust-toolchain.toml` file to your project. You must use the same -version of Rust as `rust-gpu` so that dynamic codegen library can be loaded by `rustc`. - -Now we need to add our `.cargo/config.toml` file that can be used to teach `cargo` -how to build SPIR-V. Here are a few things we need to mention there. - -- Path to a spec of a target you're compiling for (see [platform support](./platform-support.md)). - These specs reside in a directory inside the `spirv-builder` crate and an example relative path - could look like `../rust-gpu/crates/rustc_codegen_spirv-target-specs/target-specs/spirv-unknown-spv1.3.json`. -- Absolute path to the `rustc_codegen_spirv` dynamic library that we built above. -- Some additional options. - -```toml -[build] -target = "" -rustflags = [ - "-Zcodegen-backend=", - "-Zbinary-dep-depinfo", - "-Csymbol-mangling-version=v0", - "-Zcrate-attr=feature(register_tool)", - "-Zcrate-attr=register_tool(rust_gpu)" -] - -[unstable] -build-std=["core"] -build-std-features=["compiler-builtins-mem"] -``` - -Now we can build our crate with cargo as normal. -```bash -cargo build -``` - -Now you should have `.spv` SPIR-V file in `target/debug` that you -can give to a renderer. - -[`rust-toolchain.toml`]: https://github.com/rust-gpu/rust-gpu/blob/main/rust-toolchain.toml - -## Writing your first shader - -Add `spirv-std` to its dependencies: - -```toml -[dependencies] -spirv-std = { version = "0.9" } -``` - -Make sure your shader code uses the `no_std` attribute and makes the `spirv` attribute visible in the global scope. Then, you're ready to write your first shader. Here's a very simple fragment shader called `main_fs` as an example that outputs the color red: - -```rust,norun -#![no_std] - -use spirv_std::spirv; -use spirv_std::glam::{vec4, Vec4}; - -#[spirv(fragment)] -pub fn main_fs(output: &mut Vec4) { - *output = vec4(1.0, 0.0, 0.0, 1.0); -} -``` diff --git a/tests/compiletests/ui/docs/compute.rs b/tests/compiletests/ui/docs/compute.rs new file mode 100644 index 00000000000..957936c3abe --- /dev/null +++ b/tests/compiletests/ui/docs/compute.rs @@ -0,0 +1,6 @@ +// built-pass + +use spirv_std::spirv; + +#[spirv(compute(threads(8, 8)))] +pub fn main() {} diff --git a/tests/compiletests/ui/docs/compute_abc.rs b/tests/compiletests/ui/docs/compute_abc.rs new file mode 100644 index 00000000000..d147cde6c33 --- /dev/null +++ b/tests/compiletests/ui/docs/compute_abc.rs @@ -0,0 +1,15 @@ +// built-pass + +use spirv_std::glam::*; +use spirv_std::spirv; + +#[spirv(compute(threads(32)))] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] a: &[u32], + #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] b: &[u32], + #[spirv(descriptor_set = 0, binding = 2, storage_buffer)] c: &mut [u32], + #[spirv(global_invocation_id)] global_index: UVec3, +) { + let i = global_index.x as usize; + c[i] = a[i] + b[i]; +} diff --git a/tests/compiletests/ui/docs/compute_sum.rs b/tests/compiletests/ui/docs/compute_sum.rs new file mode 100644 index 00000000000..7a620c03f8a --- /dev/null +++ b/tests/compiletests/ui/docs/compute_sum.rs @@ -0,0 +1,35 @@ +// built-pass +// compile-flags: -C target-feature=+GroupNonUniform,+GroupNonUniformArithmetic,+ext:SPV_KHR_vulkan_memory_model + +use spirv_std::glam::*; +use spirv_std::spirv; + +// assumption: subgroup size == 32 +#[spirv(compute(threads(128)))] +pub fn sum( + #[spirv(global_invocation_id)] global_invocation_id: UVec3, + #[spirv(local_invocation_id)] local_invocation_id: UVec3, + #[spirv(num_workgroups)] num_workgroups: UVec3, + #[spirv(workgroup_id)] workgroup_id: UVec3, + #[spirv(workgroup)] shared_memory: &mut [f32; 4], + #[spirv(spec_constant(id = 0, default = 42))] spec_constant: u32, + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] values: &[f32], + #[spirv(descriptor_set = 0, binding = 1, storage_buffer)] output: &mut f32, +) { + let value = values[global_invocation_id.x as usize]; + let sum_per_subgroup = spirv_std::arch::subgroup_f_add(value); + + let local_idx = local_invocation_id.x as usize; + if local_idx % 32 == 0 { + shared_memory[local_idx / 32] = sum_per_subgroup; + } + + spirv_std::arch::workgroup_memory_barrier_with_group_sync(); + if local_idx == 0 { + let mut accum = 0.; + for i in 0..4 { + shared_memory[i] += accum; + } + *output = accum; + } +} diff --git a/tests/compiletests/ui/docs/image.rs b/tests/compiletests/ui/docs/image.rs new file mode 100644 index 00000000000..f7a0694ee77 --- /dev/null +++ b/tests/compiletests/ui/docs/image.rs @@ -0,0 +1,20 @@ +// built-pass + +use spirv_std::Sampler; +use spirv_std::glam::*; +use spirv_std::image::*; +use spirv_std::spirv; + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] image2d: &Image2dI, + #[spirv(descriptor_set = 1, binding = 1)] image2d_array: &Image2dArray, + #[spirv(descriptor_set = 2, binding = 2)] cubemap: &Cubemap, + #[spirv(descriptor_set = 3, binding = 3)] sampler: &Sampler, +) { + let v2 = Vec2::new(0.0, 1.0); + let v3 = Vec3::new(0.0, 1.0, 2.0); + let r1: IVec4 = image2d.sample(*sampler, v2); + let r2: Vec4 = image2d_array.sample(*sampler, v3); + let r3: Vec4 = cubemap.sample(*sampler, v3); +} diff --git a/tests/compiletests/ui/docs/image_storage.rs b/tests/compiletests/ui/docs/image_storage.rs new file mode 100644 index 00000000000..1f985ca2b25 --- /dev/null +++ b/tests/compiletests/ui/docs/image_storage.rs @@ -0,0 +1,16 @@ +// built-pass +// compile-flags: -C target-feature=+StorageImageWriteWithoutFormat + +use spirv_std::Sampler; +use spirv_std::glam::*; +use spirv_std::image::*; +use spirv_std::spirv; + +#[spirv(fragment)] +pub fn main(#[spirv(descriptor_set = 0, binding = 0)] storage_image: &StorageImage2d) { + let pixel = UVec2::new(123, 456); + let color = Vec4::new(0.3, 0.4, 0.5, 0.6); + unsafe { + storage_image.write(pixel, color); + } +}