Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor and document storage classes #280

Merged
merged 2 commits into from
Nov 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/spirv-builder/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ spirv-std = { path = "../../crates/spirv-std" }
static SRC_PREFIX: &str = r#"#![no_std]
#![feature(register_attr, asm)]
#![register_attr(spirv)]
#[allow(unused_imports)]
#![allow(unused_imports)]
use spirv_std::*;
use spirv_std::storage_class::*;
"#;

fn setup(src: &str) -> Result<PathBuf, Box<dyn Error>> {
Expand Down
57 changes: 1 addition & 56 deletions crates/spirv-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
nonstandard_style
)]

pub mod storage_class;
mod textures;

pub use glam;
Expand All @@ -53,62 +54,6 @@ fn panic(_: &core::panic::PanicInfo<'_>) -> ! {
#[lang = "eh_personality"]
extern "C" fn rust_eh_personality() {}

macro_rules! pointer_addrspace_write {
(false) => {};
(true) => {
#[inline]
#[allow(unused_attributes)]
#[spirv(really_unsafe_ignore_bitcasts)]
pub fn store(&mut self, v: T) {
*self.x = v
}
};
}

macro_rules! pointer_addrspace {
($storage_class:ident, $type_name:ident, $writeable:tt) => {
#[allow(unused_attributes)]
#[spirv($storage_class)]
pub struct $type_name<'a, T> {
x: &'a mut T,
}

impl<'a, T: Copy> $type_name<'a, T> {
#[inline]
#[allow(unused_attributes)]
#[spirv(really_unsafe_ignore_bitcasts)]
pub fn load(&self) -> T {
*self.x
}

pointer_addrspace_write!($writeable);
}
};
}

// Make sure these strings stay synced with symbols.rs
// Note the type names don't have to match anything, they can be renamed (only the string must match)
pointer_addrspace!(uniform_constant, UniformConstant, false);
pointer_addrspace!(input, Input, false);
pointer_addrspace!(uniform, Uniform, true);
pointer_addrspace!(output, Output, true);
pointer_addrspace!(workgroup, Workgroup, true);
pointer_addrspace!(cross_workgroup, CrossWorkgroup, true);
pointer_addrspace!(private, Private, true);
pointer_addrspace!(function, Function, true);
pointer_addrspace!(generic, Generic, true);
pointer_addrspace!(push_constant, PushConstant, false);
pointer_addrspace!(atomic_counter, AtomicCounter, true);
pointer_addrspace!(image, Image, true);
pointer_addrspace!(storage_buffer, StorageBuffer, true);
pointer_addrspace!(callable_data_khr, CallableDataKHR, true);
pointer_addrspace!(incoming_callable_data_khr, IncomingCallableDataKHR, true);
pointer_addrspace!(ray_payload_khr, RayPayloadKHR, true);
pointer_addrspace!(hit_attribute_khr, HitAttributeKHR, true);
pointer_addrspace!(incoming_ray_payload_khr, IncomingRayPayloadKHR, true);
pointer_addrspace!(shader_record_buffer_khr, ShaderRecordBufferKHR, true);
pointer_addrspace!(physical_storage_buffer, PhysicalStorageBuffer, true);

pub trait Derivative {
fn ddx(self) -> Self;
fn ddx_fine(self) -> Self;
Expand Down
203 changes: 203 additions & 0 deletions crates/spirv-std/src/storage_class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
//! # Storage Classes
//!
//! Class of storage for declared variables. These types act as pointers to
//! values either contained in the GPU's memory. For example; `Input<f32>` points to a
//! `f32` that was provided as input from the pipeline, and `Private<f32>`
//! points to a `f32` in the GPU's global memory. Intermediate values do not
//! form a storage class, and unless stated otherwise, storage class-based
//! restrictions are not restrictions on intermediate objects and their types.

macro_rules! storage_class {
($(#[$($meta:meta)+])* storage_class $name:ident ; $($tt:tt)*) => {
$(#[$($meta)+])*
#[allow(unused_attributes)]
pub struct $name<'value, T> {
value: &'value mut T,
}

impl<T: Copy> $name<'_, T> {
/// Load the value into memory.
#[inline]
#[allow(unused_attributes)]
#[spirv(really_unsafe_ignore_bitcasts)]
pub fn load(&self) -> T {
*self.value
}
}

storage_class!($($tt)*);
};

// Methods available on writeable storage classes.
($(#[$($meta:meta)+])* writeable storage_class $name:ident $($tt:tt)+) => {
storage_class!($(#[$($meta)+])* storage_class $name $($tt)+);

impl <T: Copy> $name<'_, T> {
/// Store the value in storage.
#[inline]
#[allow(unused_attributes)]
#[spirv(really_unsafe_ignore_bitcasts)]
pub fn store(&mut self, v: T) {
*self.value = v
}

/// A convenience function to load a value into memory and store it.
pub fn then(&mut self, then: impl FnOnce(T) -> T) {
self.store((then)(self.load()));
}
}
};

(;) => {};
() => {};
}

// Make sure the `#[spirv(<string>)]` strings stay synced with symbols.rs
// in `rustc_codegen_spirv`.
storage_class! {
/// Graphics uniform memory. OpenCL constant memory.
///
/// Shared externally, visible across all functions in all invocations in
/// all work groups. Variables declared with this storage class are
/// read-only. They may have initializers, as allowed by the client API.
#[spirv(uniform_constant)] storage_class UniformConstant;

/// Input from pipeline.
///
/// Visible across all functions in the current invocation. Variables
/// declared with this storage class are read-only, and must not
/// have initializers.
#[spirv(input)] storage_class Input;

/// Graphics uniform blocks and buffer blocks.
///
/// Shared externally, visible across all functions in all invocations in
/// all work groups. Requires "Shader" capability.
#[spirv(uniform)] writeable storage_class Uniform;

/// Output to pipeline.
///
/// Visible across all functions in the current invocation.
#[spirv(output)] writeable storage_class Output;

/// The OpenGL "shared" storage qualifier. OpenCL local memory.
///
/// Shared across all invocations within a work group. Visible across
/// all functions.
#[spirv(workgroup)] writeable storage_class Workgroup;

/// OpenCL global memory.
///
/// Visible across all functions of all invocations of all work groups.
#[spirv(cross_workgroup)] writeable storage_class CrossWorkgroup;

/// Regular global memory.
///
/// Visible to all functions in the current invocation. Requires
/// "Shader" capability.
#[spirv(private)] writeable storage_class Private;

/// Regular function memory.
///
/// Visible only within the declaring function of the current invocation.
#[spirv(function)] writeable storage_class Function;

/// For generic pointers, which overload the [`Function`], [`Workgroup`],
/// and [`CrossWorkgroup`] Storage Classes.
#[spirv(generic)] writeable storage_class Generic;

/// Push-constant memory.
///
/// Visible across all functions in all invocations in all work groups.
/// Intended to contain a small bank of values pushed from the client API.
/// Variables declared with this storage class are read-only, and must not
/// have initializers.
#[spirv(push_constant)] storage_class PushConstant;

/// Atomic counter-specific memory.
///
/// For holding atomic counters. Visible across all functions of the
/// current invocation.
#[spirv(atomic_counter)] writeable storage_class AtomicCounter;

/// Image memory.
///
/// A traditional texture or image; SPIR-V has this single name for these.
/// An image does not include any information about how to access, filter,
/// or sample it.
#[spirv(image)] writeable storage_class Image;

/// Graphics storage buffers (buffer blocks).
///
/// Shared externally, readable and writable, visible across all functions
/// in all invocations in all work groups.
#[spirv(storage_buffer)] writeable storage_class StorageBuffer;

/// Used for storing arbitrary data associated with a ray to pass
/// to callables. (Requires `SPV_KHR_ray_tracing` extension)
///
/// Visible across all functions in the current invocation. Not shared
/// externally. Variables declared with this storage class can be both read
/// and written to. Only allowed in `RayGenerationKHR`, `ClosestHitKHR`,
/// `CallableKHR`, and `MissKHR` execution models.
#[spirv(callable_data_khr)] writeable storage_class CallableDataKHR;

/// Used for storing arbitrary data from parent sent to current callable
/// stage invoked from an `executeCallable` call. (Requires
/// `SPV_KHR_ray_tracing` extension)
///
/// Visible across all functions in current invocation. Not shared
/// externally. Variables declared with the storage class are allowed only
/// in `CallableKHR` execution models. Can be both read and written to in
/// above execution models.
#[spirv(incoming_callable_data_khr)] writeable storage_class IncomingCallableDataKHR;

/// Used for storing payload data associated with a ray. (Requires
/// `SPV_KHR_ray_tracing` extension)
///
/// Visible across all functions in the current invocation. Not shared
/// externally. Variables declared with this storage class can be both read
/// and written to. Only allowed in `RayGenerationKHR`, `AnyHitKHR`,
/// `ClosestHitKHR` and `MissKHR` execution models.
#[spirv(ray_payload_khr)] writeable storage_class RayPayloadKHR;


/// Used for storing attributes of geometry intersected by a ray. (Requires
/// `SPV_KHR_ray_tracing` extension)
///
/// Visible across all functions in the current invocation. Not shared
/// externally. Variables declared with this storage class are allowed only
/// in `IntersectionKHR`, `AnyHitKHR` and `ClosestHitKHR` execution models.
/// They can be written to only in `IntersectionKHR` execution model and read
/// from only in `AnyHitKHR` and `ClosestHitKHR` execution models.
#[spirv(hit_attribute_khr)] writeable storage_class HitAttributeKHR;


/// Used for storing attributes of geometry intersected by a ray. (Requires
/// `SPV_KHR_ray_tracing` extension)
///
/// Visible across all functions in the current invocation. Not shared
/// externally. Variables declared with this storage class are allowed only
/// in `IntersectionKHR`, `AnyHitKHR` and `ClosestHitKHR` execution models.
/// They can be written to only in `IntersectionKHR` execution model and
/// read from only in `AnyHitKHR` and `ClosestHitKHR` execution models. They
/// cannot have initializers.
#[spirv(incoming_ray_payload_khr)] writeable storage_class IncomingRayPayloadKHR;

/// Used for storing data in shader record associated with each unique
/// shader in ray_tracing pipeline. (Requires
/// `SPV_KHR_ray_tracing` extension)
///
/// Visible across all functions in current invocation. Can be initialized
/// externally via API. Variables declared with this storage class are
/// allowed in RayGenerationKHR, IntersectionKHR, AnyHitKHR, ClosestHitKHR,
/// MissKHR and CallableKHR execution models, are read-only, and cannot have
/// initializers. Refer to the client API for details on shader records.
#[spirv(shader_record_buffer_khr)] writeable storage_class ShaderRecordBufferKHR;

/// Graphics storage buffers using physical addressing. (SPIR-V 1.5+)
///
/// Shared externally, readable and writable, visible across all functions
/// in all invocations in all work groups.
#[spirv(physical_storage_buffer)] writeable storage_class PhysicalStorageBuffer;
}
2 changes: 1 addition & 1 deletion examples/shaders/simplest-shader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![register_attr(spirv)]

use spirv_std::glam::Vec4;
use spirv_std::{Input, Output};
use spirv_std::storage_class::{Input, Output};

#[allow(unused_attributes)]
#[spirv(fragment)]
Expand Down
2 changes: 1 addition & 1 deletion examples/shaders/sky-shader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use core::f32::consts::PI;
use shared::*;
use spirv_std::glam::{const_vec3, Vec2, Vec3, Vec4};
use spirv_std::{Input, Output, PushConstant};
use spirv_std::storage_class::{Input, Output, PushConstant};

// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but
// we tie #[no_std] above to the same condition, so it's fine.
Expand Down