mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-21 22:34:34 +00:00
Add memory_barrier and control_barrier (#519)
This commit is contained in:
parent
40359bdb56
commit
dd60da0be6
@ -6,10 +6,14 @@
|
||||
use crate::{scalar::Scalar, vector::Vector};
|
||||
|
||||
mod arithmetic;
|
||||
#[cfg(feature = "const-generics")]
|
||||
mod barrier;
|
||||
mod derivative;
|
||||
mod primitive;
|
||||
|
||||
pub use arithmetic::*;
|
||||
#[cfg(feature = "const-generics")]
|
||||
pub use barrier::*;
|
||||
pub use derivative::*;
|
||||
pub use primitive::*;
|
||||
|
||||
|
77
crates/spirv-std/src/arch/barrier.rs
Normal file
77
crates/spirv-std/src/arch/barrier.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use crate::memory::{Scope, Semantics};
|
||||
|
||||
/// Wait for other invocations of this module to reach the current point
|
||||
/// of execution.
|
||||
///
|
||||
/// All invocations of this module within Execution scope reach this point of
|
||||
/// execution before any invocation proceeds beyond it.
|
||||
///
|
||||
/// When Execution is [`Scope::Workgroup`] or larger, behavior is undefined
|
||||
/// unless all invocations within Execution execute the same dynamic instance of
|
||||
/// this instruction. When Execution is Subgroup or Invocation, the behavior of
|
||||
/// this instruction in non-uniform control flow is defined by the client API.
|
||||
///
|
||||
/// If [`Semantics`] is not [`Semantics::None`], this instruction also serves as
|
||||
/// an [`memory_barrier`] function call, and also performs and adheres to the
|
||||
/// description and semantics of an [`memory_barrier`] function with the same
|
||||
/// `MEMORY` and `SEMANTICS` operands. This allows atomically specifying both a
|
||||
/// control barrier and a memory barrier (that is, without needing two
|
||||
/// instructions). If [`Semantics`] is [`Semantics::None`], `MEMORY` is ignored.
|
||||
///
|
||||
/// Before SPIRV-V version 1.3, it is only valid to use this instruction with
|
||||
/// `TessellationControl`, `GLCompute`, or `Kernel` execution models. There is
|
||||
/// no such restriction starting with version 1.3.
|
||||
///
|
||||
/// If used with the `TessellationControl` execution model, it also implicitly
|
||||
/// synchronizes the [`crate::storage_class::Output`] Storage Class: Writes to
|
||||
/// `Output` variables performed by any invocation executed prior to a
|
||||
/// [`control_barrier`] are visible to any other invocation proceeding beyond
|
||||
/// that [`control_barrier`].
|
||||
#[spirv_std_macros::gpu_only]
|
||||
#[doc(alias = "OpControlBarrier")]
|
||||
#[inline]
|
||||
pub unsafe fn control_barrier<
|
||||
const EXECUTION: Scope,
|
||||
const MEMORY: Scope,
|
||||
const SEMANTICS: Semantics,
|
||||
>() {
|
||||
asm! {
|
||||
"%u32 = OpTypeInt 32 0",
|
||||
"%execution = OpConstant %u32 {execution}",
|
||||
"%memory = OpConstant %u32 {memory}",
|
||||
"%semantics = OpConstant %u32 {semantics}",
|
||||
"OpControlBarrier %execution %memory %semantics",
|
||||
execution = const EXECUTION as u8,
|
||||
memory = const MEMORY as u8,
|
||||
semantics = const SEMANTICS as u8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Control the order that memory accesses are observed.
|
||||
///
|
||||
/// Ensures that memory accesses issued before this instruction are observed
|
||||
/// before memory accesses issued after this instruction. This control is
|
||||
/// ensured only for memory accesses issued by this invocation and observed by
|
||||
/// another invocation executing within `MEMORY` scope. If the `vulkan` memory
|
||||
/// model is declared, this ordering only applies to memory accesses that
|
||||
/// use the `NonPrivatePointer` memory operand or `NonPrivateTexel`
|
||||
/// image operand.
|
||||
///
|
||||
/// `SEMANTICS` declares what kind of memory is being controlled and what kind
|
||||
/// of control to apply.
|
||||
///
|
||||
/// To execute both a memory barrier and a control barrier,
|
||||
/// see [`control_barrier`].
|
||||
#[spirv_std_macros::gpu_only]
|
||||
#[doc(alias = "OpMemoryBarrier")]
|
||||
#[inline]
|
||||
pub unsafe fn memory_barrier<const MEMORY: Scope, const SEMANTICS: Semantics>() {
|
||||
asm! {
|
||||
"%u32 = OpTypeInt 32 0",
|
||||
"%memory = OpConstant %u32 {memory}",
|
||||
"%semantics = OpConstant %u32 {semantics}",
|
||||
"OpMemoryBarrier %memory %semantics",
|
||||
memory = const MEMORY as u8,
|
||||
semantics = const SEMANTICS as u8,
|
||||
}
|
||||
}
|
@ -4,6 +4,11 @@
|
||||
feature(asm, register_attr, repr_simd, core_intrinsics, lang_items),
|
||||
register_attr(spirv)
|
||||
)]
|
||||
#![cfg_attr(
|
||||
feature = "const-generics",
|
||||
feature(const_generics),
|
||||
allow(incomplete_features)
|
||||
)]
|
||||
// BEGIN - Embark standard lints v0.3
|
||||
// do not change or add/remove here, but one can add exceptions after this section
|
||||
// for more info see: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59>
|
||||
@ -72,6 +77,7 @@ pub extern crate spirv_std_macros as macros;
|
||||
pub mod arch;
|
||||
pub mod float;
|
||||
pub mod integer;
|
||||
pub mod memory;
|
||||
pub mod scalar;
|
||||
pub(crate) mod sealed;
|
||||
mod textures;
|
||||
|
92
crates/spirv-std/src/memory.rs
Normal file
92
crates/spirv-std/src/memory.rs
Normal file
@ -0,0 +1,92 @@
|
||||
//! Types for handling memory ordering constraints for concurrent memory access.
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Scope {
|
||||
/// Crosses multiple devices.
|
||||
CrossDevice = 0,
|
||||
|
||||
/// The current device.
|
||||
Device = 1,
|
||||
|
||||
/// The current workgroup.
|
||||
Workgroup = 2,
|
||||
|
||||
/// The current subgroup.
|
||||
Subgroup = 3,
|
||||
|
||||
/// The current invocation.
|
||||
Invocation = 4,
|
||||
|
||||
/// The current queue family.
|
||||
QueueFamily = 5,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Semantics {
|
||||
/// No memory semantics.
|
||||
None = 0,
|
||||
|
||||
/// On an atomic instruction, orders memory operations provided in program
|
||||
/// order after this atomic instruction against this atomic instruction. On
|
||||
/// a barrier, orders memory operations provided in program order after this
|
||||
/// barrier against atomic instructions before this barrier.
|
||||
Acquire = 0x2,
|
||||
|
||||
/// On an atomic instruction, orders memory operations provided in program
|
||||
/// order before this atomic instruction against this atomic instruction. On
|
||||
/// a barrier, orders memory operations provided in program order before
|
||||
/// this barrier against atomic instructions after this barrier.
|
||||
Release = 0x4,
|
||||
|
||||
/// Has the properties of both [`Self::Acquire`] and [`Self::Release`] semantics. It
|
||||
/// is used for read-modify-write operations.
|
||||
AcquireRelease = 0x8,
|
||||
|
||||
/// All observers see this memory access in the same order with respect to
|
||||
/// other sequentially-consistent memory accesses from this invocation.
|
||||
/// If the declared memory model is `vulkan`, `SequentiallyConsistent` must
|
||||
/// not be used.
|
||||
SequentiallyConsistent = 0x10,
|
||||
|
||||
/// Apply the memory-ordering constraints to
|
||||
/// [`crate::storage_class::StorageBuffer`],
|
||||
/// [`crate::storage_class::PhysicalStorageBuffer`], or
|
||||
/// [`crate::storage_class::Uniform`] Storage Class memory.
|
||||
UniformMemory = 0x40,
|
||||
|
||||
/// Apply the memory-ordering constraints to subgroup memory.
|
||||
SubgroupMemory = 0x80,
|
||||
|
||||
/// Apply the memory-ordering constraints to
|
||||
/// [`crate::storage_class::Workgroup`] Storage Class memory.
|
||||
WorkgroupMemory = 0x100,
|
||||
|
||||
/// Apply the memory-ordering constraints to
|
||||
/// [`crate::storage_class::CrossWorkgroup`] Storage Class memory.
|
||||
CrossWorkgroupMemory = 0x200,
|
||||
|
||||
/// Apply the memory-ordering constraints to
|
||||
/// [`crate::storage_class::AtomicCounter`] Storage Class memory.
|
||||
AtomicCounterMemory = 0x400,
|
||||
|
||||
/// Apply the memory-ordering constraints to image contents (types declared
|
||||
/// by `OpTypeImage`), or to accesses done through pointers to the
|
||||
/// [`crate::storage_class::Image`] Storage Class.
|
||||
ImageMemory = 0x800,
|
||||
|
||||
/// Apply the memory-ordering constraints to the
|
||||
/// [`crate::storage_class::Output`] Storage Class memory.
|
||||
OutputMemory = 0x1000,
|
||||
|
||||
/// Perform an availability operation on all references in the selected
|
||||
/// storage classes.
|
||||
MakeAvailable = 0x2000,
|
||||
|
||||
/// Perform a visibility operation on all references in the selected
|
||||
/// storage classes.
|
||||
MakeVisible = 0x4000,
|
||||
|
||||
/// This access cannot be eliminated, duplicated, or combined with
|
||||
/// other accesses.
|
||||
Volatile = 0x8000,
|
||||
}
|
17
tests/ui/arch/control_barrier.rs
Normal file
17
tests/ui/arch/control_barrier.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// build-pass
|
||||
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use spirv_std::memory::{Scope, Semantics};
|
||||
|
||||
#[spirv(fragment)]
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
spirv_std::arch::control_barrier::<
|
||||
{ Scope::Workgroup },
|
||||
{ Scope::Workgroup },
|
||||
{ Semantics::None },
|
||||
>();
|
||||
}
|
||||
}
|
16
tests/ui/arch/memory_barrier.rs
Normal file
16
tests/ui/arch/memory_barrier.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// build-pass
|
||||
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use spirv_std::memory::{Scope, Semantics};
|
||||
|
||||
#[spirv(fragment)]
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
spirv_std::arch::memory_barrier::<
|
||||
{ Scope::Workgroup },
|
||||
{ Semantics::None },
|
||||
>();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user