Skip to content

Commit cbc2027

Browse files
committed
Add memory_barrier and control_barrier
1 parent 3274778 commit cbc2027

File tree

6 files changed

+212
-0
lines changed

6 files changed

+212
-0
lines changed

crates/spirv-std/src/arch.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ use crate::{scalar::Scalar, vector::Vector};
88

99
#[cfg(feature = "const-generics")]
1010
mod arithmetic;
11+
#[cfg(feature = "const-generics")]
12+
mod barrier;
1113
mod derivative;
1214

1315
#[cfg(feature = "const-generics")]
1416
pub use arithmetic::*;
17+
#[cfg(feature = "const-generics")]
18+
pub use barrier::*;
1519
pub use derivative::*;
1620

1721
/// Result is true if any component of `vector` is true, otherwise result is

crates/spirv-std/src/arch/barrier.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use crate::memory::{Scope, Semantics};
2+
3+
/// Wait for other invocations of this module to reach the current point
4+
/// of execution.
5+
///
6+
/// All invocations of this module within Execution scope reach this point of
7+
/// execution before any invocation proceeds beyond it.
8+
///
9+
/// When Execution is [`Scope::Workgroup`] or larger, behavior is undefined
10+
/// unless all invocations within Execution execute the same dynamic instance of
11+
/// this instruction. When Execution is Subgroup or Invocation, the behavior of
12+
/// this instruction in non-uniform control flow is defined by the client API.
13+
///
14+
/// If [`Semantics`] is not [`Semantics::None`], this instruction also serves as
15+
/// an [`memory_barrier`] function call, and also performs and adheres to the
16+
/// description and semantics of an [`memory_barrier`] function with the same
17+
/// `MEMORY` and `SEMANTICS` operands. This allows atomically specifying both a
18+
/// control barrier and a memory barrier (that is, without needing two
19+
/// instructions). If [`Semantics`] is [`Semantics::None`], `MEMORY` is ignored.
20+
///
21+
/// Before SPIRV-V version 1.3, it is only valid to use this instruction with
22+
/// `TessellationControl`, `GLCompute`, or `Kernel` execution models. There is
23+
/// no such restriction starting with version 1.3.
24+
///
25+
/// If used with the `TessellationControl` execution model, it also implicitly
26+
/// synchronizes the [`crate::storage_class::Output`] Storage Class: Writes to
27+
/// `Output` variables performed by any invocation executed prior to a
28+
/// [`control_barrier`] are visible to any other invocation proceeding beyond
29+
/// that [`control_barrier`].
30+
#[spirv_std_macros::gpu_only]
31+
#[doc(alias = "OpControlBarrier")]
32+
#[inline]
33+
pub unsafe fn control_barrier<
34+
const EXECUTION: Scope,
35+
const MEMORY: Scope,
36+
const SEMANTICS: Semantics,
37+
>() {
38+
asm! {
39+
"%u32 = OpTypeInt 32 0",
40+
"%execution = OpConstant %u32 {execution}",
41+
"%memory = OpConstant %u32 {memory}",
42+
"%semantics = OpConstant %u32 {semantics}",
43+
"OpControlBarrier %execution %memory %semantics",
44+
execution = const EXECUTION as u8,
45+
memory = const MEMORY as u8,
46+
semantics = const SEMANTICS as u8,
47+
}
48+
}
49+
50+
/// Control the order that memory accesses are observed.
51+
///
52+
/// Ensures that memory accesses issued before this instruction are observed
53+
/// before memory accesses issued after this instruction. This control is
54+
/// ensured only for memory accesses issued by this invocation and observed by
55+
/// another invocation executing within `MEMORY` scope. If the `vulkan` memory
56+
/// model is declared, this ordering only applies to memory accesses that
57+
/// use the `NonPrivatePointer` memory operand or `NonPrivateTexel`
58+
/// image operand.
59+
///
60+
/// `SEMANTICS` declares what kind of memory is being controlled and what kind
61+
/// of control to apply.
62+
///
63+
/// To execute both a memory barrier and a control barrier,
64+
/// see [`control_barrier`].
65+
#[spirv_std_macros::gpu_only]
66+
#[doc(alias = "OpMemoryBarrier")]
67+
#[inline]
68+
pub unsafe fn memory_barrier<const MEMORY: Scope, const SEMANTICS: Semantics>() {
69+
asm! {
70+
"%u32 = OpTypeInt 32 0",
71+
"%memory = OpConstant %u32 {memory}",
72+
"%semantics = OpConstant %u32 {semantics}",
73+
"OpMemoryBarrier %memory %semantics",
74+
memory = const MEMORY as u8,
75+
semantics = const SEMANTICS as u8,
76+
}
77+
}

crates/spirv-std/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
feature(asm, register_attr, repr_simd, core_intrinsics, lang_items),
55
register_attr(spirv)
66
)]
7+
#![cfg_attr(
8+
feature = "const-generics",
9+
feature(const_generics),
10+
allow(incomplete_features)
11+
)]
712
// BEGIN - Embark standard lints v0.3
813
// do not change or add/remove here, but one can add exceptions after this section
914
// for more info see: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59>
@@ -72,6 +77,7 @@ pub extern crate spirv_std_macros as macros;
7277
pub mod arch;
7378
pub mod float;
7479
pub mod integer;
80+
pub mod memory;
7581
pub mod scalar;
7682
pub(crate) mod sealed;
7783
pub mod storage_class;

crates/spirv-std/src/memory.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! Types for handling memory ordering constraints for concurrent memory access.
2+
3+
#[derive(Debug, PartialEq, Eq)]
4+
pub enum Scope {
5+
/// Crosses multiple devices.
6+
CrossDevice = 0,
7+
8+
/// The current device.
9+
Device = 1,
10+
11+
/// The current workgroup.
12+
Workgroup = 2,
13+
14+
/// The current subgroup.
15+
Subgroup = 3,
16+
17+
/// The current invocation.
18+
Invocation = 4,
19+
20+
/// The current queue family.
21+
QueueFamily = 5,
22+
}
23+
24+
#[derive(Debug, PartialEq, Eq)]
25+
pub enum Semantics {
26+
/// No memory semantics.
27+
None = 0,
28+
29+
/// On an atomic instruction, orders memory operations provided in program
30+
/// order after this atomic instruction against this atomic instruction. On
31+
/// a barrier, orders memory operations provided in program order after this
32+
/// barrier against atomic instructions before this barrier.
33+
Acquire = 0x2,
34+
35+
/// On an atomic instruction, orders memory operations provided in program
36+
/// order before this atomic instruction against this atomic instruction. On
37+
/// a barrier, orders memory operations provided in program order before
38+
/// this barrier against atomic instructions after this barrier.
39+
Release = 0x4,
40+
41+
/// Has the properties of both [`Self::Acquire`] and [`Self::Release`] semantics. It
42+
/// is used for read-modify-write operations.
43+
AcquireRelease = 0x8,
44+
45+
/// All observers see this memory access in the same order with respect to
46+
/// other sequentially-consistent memory accesses from this invocation.
47+
/// If the declared memory model is `vulkan`, `SequentiallyConsistent` must
48+
/// not be used.
49+
SequentiallyConsistent = 0x10,
50+
51+
/// Apply the memory-ordering constraints to
52+
/// [`crate::storage_class::StorageBuffer`],
53+
/// [`crate::storage_class::PhysicalStorageBuffer`], or
54+
/// [`crate::storage_class::Uniform`] Storage Class memory.
55+
UniformMemory = 0x40,
56+
57+
/// Apply the memory-ordering constraints to subgroup memory.
58+
SubgroupMemory = 0x80,
59+
60+
/// Apply the memory-ordering constraints to
61+
/// [`crate::storage_class::Workgroup`] Storage Class memory.
62+
WorkgroupMemory = 0x100,
63+
64+
/// Apply the memory-ordering constraints to
65+
/// [`crate::storage_class::CrossWorkgroup`] Storage Class memory.
66+
CrossWorkgroupMemory = 0x200,
67+
68+
/// Apply the memory-ordering constraints to
69+
/// [`crate::storage_class::AtomicCounter`] Storage Class memory.
70+
AtomicCounterMemory = 0x400,
71+
72+
/// Apply the memory-ordering constraints to image contents (types declared
73+
/// by `OpTypeImage`), or to accesses done through pointers to the
74+
/// [`crate::storage_class::Image`] Storage Class.
75+
ImageMemory = 0x800,
76+
77+
/// Apply the memory-ordering constraints to the
78+
/// [`crate::storage_class::Output`] Storage Class memory.
79+
OutputMemory = 0x1000,
80+
81+
/// Perform an availability operation on all references in the selected
82+
/// storage classes.
83+
MakeAvailable = 0x2000,
84+
85+
/// Perform a visibility operation on all references in the selected
86+
/// storage classes.
87+
MakeVisible = 0x4000,
88+
89+
/// This access cannot be eliminated, duplicated, or combined with
90+
/// other accesses.
91+
Volatile = 0x8000,
92+
}

tests/ui/arch/control_barrier.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// build-pass
2+
3+
#![feature(const_generics)]
4+
#![allow(incomplete_features)]
5+
6+
use spirv_std::memory::{Scope, Semantics};
7+
8+
#[spirv(fragment)]
9+
pub fn main() {
10+
unsafe {
11+
spirv_std::arch::control_barrier::<
12+
{ Scope::Workgroup },
13+
{ Scope::Workgroup },
14+
{ Semantics::None },
15+
>();
16+
}
17+
}

tests/ui/arch/memory_barrier.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// build-pass
2+
3+
#![feature(const_generics)]
4+
#![allow(incomplete_features)]
5+
6+
use spirv_std::memory::{Scope, Semantics};
7+
8+
#[spirv(fragment)]
9+
pub fn main() {
10+
unsafe {
11+
spirv_std::arch::memory_barrier::<
12+
{ Scope::Workgroup },
13+
{ Semantics::None },
14+
>();
15+
}
16+
}

0 commit comments

Comments
 (0)