#[cfg(feature = "cuda")]
mod device;
pub mod ffi;
pub mod header;
pub mod pinned;
pub mod slot;
pub mod spsc;
#[cfg(feature = "cuda")]
pub mod gpu_arena;
#[cfg(feature = "cuda")]
pub use device::DeviceBuffer;
pub use ffi::*;
pub use header::Header;
pub use slot::Slot;
pub use spsc::{Consumer, Producer, Message};
#[cfg(feature = "cuda")]
pub use gpu_arena::{GpuTextArena, PackedStreamContext};
pub use self::pinned::Pinned;
use std::ptr;
pub struct Buffer {
pinned: Pinned,
stream: u64, }
impl Buffer {
pub fn new(n_slots: usize) -> Result<Self, String> {
if !n_slots.is_power_of_two() {
return Err("n_slots must be a power of 2".to_string());
}
#[cfg(feature = "cuda")]
{
if unsafe { ffi::cuda_init_device(0) } >= 0 {
println!("✓ Using NVIDIA CUDA acceleration");
return Self::new_cuda(n_slots);
}
println!("CUDA not available, trying WebGPU...");
}
#[cfg(feature = "webgpu")]
{
if let Ok(buffer) = Self::new_webgpu(n_slots) {
println!("✓ Using WebGPU acceleration");
return Ok(buffer);
}
println!("WebGPU not available, falling back to CPU...");
}
println!("⚠️ WARNING: Running in CPU-only mode (demo/testing only)");
println!(" GPU acceleration is required for production use!");
Self::new_cpu_fallback(n_slots)
}
#[cfg(feature = "webgpu")]
fn new_webgpu(n_slots: usize) -> Result<Self, String> {
use crate::webgpu::WebGpuBuffer;
let _webgpu_buffer = WebGpuBuffer::new(n_slots)?;
Self::new_cpu_fallback(n_slots)
}
fn new_cpu_fallback(n_slots: usize) -> Result<Self, String> {
use std::alloc::{alloc_zeroed, Layout};
let header_layout = Layout::new::<Header>();
let slots_layout = Layout::array::<Slot>(n_slots).map_err(|e| e.to_string())?;
let header_ptr = unsafe {
let ptr = alloc_zeroed(header_layout) as *mut Header;
if ptr.is_null() {
return Err("Failed to allocate header memory".to_string());
}
(*ptr).config.slot_count = n_slots as u32;
(*ptr).config.wrap_mask = (n_slots - 1) as u64;
(*ptr).config.payload_size = 240;
(*ptr).config.batch_size = 64;
(*ptr).producer.write_idx.store(0, std::sync::atomic::Ordering::Relaxed);
(*ptr).consumer.read_idx.store(0, std::sync::atomic::Ordering::Relaxed);
ptr
};
let slots_ptr = unsafe {
let ptr = alloc_zeroed(slots_layout) as *mut Slot;
if ptr.is_null() {
return Err("Failed to allocate slots memory".to_string());
}
ptr
};
Ok(Self {
pinned: Pinned {
header: header_ptr,
slots: slots_ptr,
n_slots,
},
stream: 0,
})
}
#[cfg(feature = "cuda")]
fn new_cuda(n_slots: usize) -> Result<Self, String> {
if unsafe { ffi::cuda_init_device(0) } < 0 {
return Err("Failed to initialize CUDA device".to_string());
}
let mut slots_ptr: *mut Slot = ptr::null_mut();
let mut header_ptr: *mut Header = ptr::null_mut();
let result = unsafe {
ffi::init_unified_buffer(
&mut slots_ptr,
&mut header_ptr,
n_slots as std::os::raw::c_int,
)
};
if result != 0 || header_ptr.is_null() || slots_ptr.is_null() {
return Err("Failed to initialize unified buffer".to_string());
}
Ok(Self {
pinned: Pinned {
header: header_ptr,
slots: slots_ptr,
n_slots,
},
stream: 0, })
}
pub fn split(self) -> (Producer<'static>, Consumer<'static>) {
let arc_pinned = std::sync::Arc::new(self.pinned);
let producer = Producer::new(arc_pinned.clone());
let consumer = Consumer::new(arc_pinned);
(producer, consumer)
}
pub fn split_mut<'a>(&'a mut self) -> (Producer<'a>, Consumer<'a>) {
let pinned_ptr = &mut self.pinned as *mut Pinned;
unsafe {
let producer = Producer::new_from_ref(&*pinned_ptr);
let consumer = Consumer::new_from_ref(&*pinned_ptr);
(producer, consumer)
}
}
pub fn as_raw_parts(&self) -> (*mut Header, *mut Slot) {
(self.pinned.as_header(), self.pinned.as_slots())
}
}