nuvec_gpu/lib.rs
1//! Metal backend: device discovery, kernel library and pipelines, shared buffers, and
2//! command encoding with minimal barriers.
3//!
4//! ```no_run
5//! # #[cfg(target_os = "macos")]
6//! # fn main() -> nuvec_gpu::Result<()> {
7//! use nuvec_gpu::{Arg, Device};
8//!
9//! let Some(device) = Device::system_default() else { return Ok(()) }; // no Metal here
10//! let add = device.pipeline("nuvec_add_f32")?;
11//! let a = device.buffer_from(&1.0f32.to_le_bytes().repeat(4))?;
12//! let b = device.buffer_from(&2.0f32.to_le_bytes().repeat(4))?;
13//! let mut out = device.new_buffer(16)?;
14//! let mut cmd = device.command_buffer()?;
15//! let n = 4u32.to_le_bytes();
16//! let args = [Arg::read(&a), Arg::read(&b), Arg::write(&mut out), Arg::bytes(&n)];
17//! // SAFETY: `nuvec_add_f32` touches element `i < n` of each buffer; all hold 4 floats.
18//! unsafe { cmd.dispatch(&add, &args, 4)? };
19//! cmd.commit().wait()?;
20//! assert_eq!(&out.contents()?[..4], &3.0f32.to_le_bytes());
21//! # Ok(())
22//! # }
23//! # #[cfg(not(target_os = "macos"))]
24//! # fn main() {} // Metal exists only on Apple platforms
25//! ```
26//!
27//! Buffers live in shared (unified) memory: the CPU reads GPU results in place. CPU access
28//! is refused while submitted work uses a buffer, and GPU writes need `&mut Buffer`, so
29//! CPU and GPU never race on the same memory. Dispatching is `unsafe`: nuvec validates the
30//! arguments and orders the work, but cannot check that a kernel stays within its buffers.
31//!
32//! Requires macOS 15 or later (Metal 3.2, as the kernel library is built).
33//!
34//! Arrays evaluated on the GPU (`nuvec-core`) use the process-wide [`Device::shared`]; its
35//! allocator's limits and statistics are set and read there.
36//!
37//! **Stability:** no promise when this crate is depended on directly; depend on `nuvec`,
38//! whose re-exports are semver-tracked.
39
40mod error;
41mod info;
42mod memory;
43
44pub use error::{GpuError, Result};
45pub use info::{DeviceInfo, NaxReason, NaxStatus, physical_memory};
46pub use memory::{MemoryStats, allocation_size, mapping_size, page_size};
47
48#[cfg(target_os = "macos")]
49mod metal;
50#[cfg(target_os = "macos")]
51pub use metal::{
52 Arg, Buffer, CommandBuffer, Constant, Device, Event, Pending, Pipeline, Submitted, Timeline,
53 profile,
54};
55
56#[cfg(not(target_os = "macos"))]
57mod stub;
58
59#[cfg(all(feature = "cuda", target_os = "linux"))]
60pub mod cuda;
61#[cfg(not(target_os = "macos"))]
62pub use stub::{Device, profile};
63
64/// The version of this crate.
65pub const VERSION: &str = env!("CARGO_PKG_VERSION");
66
67#[cfg(test)]
68mod tests {
69 #[test]
70 fn version_is_set() {
71 assert!(!super::VERSION.is_empty());
72 let _ = nuvec_kernels::MODE;
73 }
74}