ringkernel_wgpu/
lib.rs

1//! WebGPU Backend for RingKernel
2//!
3//! This crate provides cross-platform GPU support via WebGPU (wgpu).
4//! Works on Vulkan, Metal, DX12, and browser environments.
5//!
6//! # Features
7//!
8//! - Cross-platform GPU access (Windows, macOS, Linux, Web)
9//! - Event-driven execution model (WebGPU limitation)
10//! - WGSL shader language support
11//!
12//! # Limitations
13//!
14//! - No true persistent kernels (WebGPU doesn't support cooperative groups)
15//! - No 64-bit atomics in WGSL
16//! - Event-driven execution only
17//!
18//! # Example
19//!
20//! ```ignore
21//! use ringkernel_wgpu::WgpuRuntime;
22//!
23//! #[tokio::main]
24//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
25//!     let runtime = WgpuRuntime::new().await?;
26//!     let kernel = runtime.launch("compute", Default::default()).await?;
27//!     kernel.activate().await?;
28//!     Ok(())
29//! }
30//! ```
31
32#![warn(missing_docs)]
33
34#[cfg(feature = "wgpu")]
35mod adapter;
36#[cfg(feature = "wgpu")]
37mod kernel;
38#[cfg(feature = "wgpu")]
39mod memory;
40#[cfg(feature = "wgpu")]
41mod runtime;
42#[cfg(feature = "wgpu")]
43mod shader;
44
45#[cfg(feature = "wgpu")]
46pub use adapter::WgpuAdapter;
47#[cfg(feature = "wgpu")]
48pub use kernel::WgpuKernel;
49#[cfg(feature = "wgpu")]
50pub use memory::WgpuBuffer;
51#[cfg(feature = "wgpu")]
52pub use runtime::WgpuRuntime;
53
54// Stub implementation when wgpu feature is disabled
55#[cfg(not(feature = "wgpu"))]
56mod stub {
57    use async_trait::async_trait;
58    use ringkernel_core::error::{Result, RingKernelError};
59    use ringkernel_core::runtime::{
60        Backend, KernelHandle, KernelId, LaunchOptions, RingKernelRuntime, RuntimeMetrics,
61    };
62
63    /// Stub WebGPU runtime when wgpu feature is disabled.
64    pub struct WgpuRuntime;
65
66    impl WgpuRuntime {
67        /// Create fails when wgpu is not available.
68        pub async fn new() -> Result<Self> {
69            Err(RingKernelError::BackendUnavailable(
70                "wgpu feature not enabled".to_string(),
71            ))
72        }
73    }
74
75    #[async_trait]
76    impl RingKernelRuntime for WgpuRuntime {
77        fn backend(&self) -> Backend {
78            Backend::Wgpu
79        }
80
81        fn is_backend_available(&self, _backend: Backend) -> bool {
82            false
83        }
84
85        async fn launch(&self, _kernel_id: &str, _options: LaunchOptions) -> Result<KernelHandle> {
86            Err(RingKernelError::BackendUnavailable("WebGPU".to_string()))
87        }
88
89        fn get_kernel(&self, _kernel_id: &KernelId) -> Option<KernelHandle> {
90            None
91        }
92
93        fn list_kernels(&self) -> Vec<KernelId> {
94            vec![]
95        }
96
97        fn metrics(&self) -> RuntimeMetrics {
98            RuntimeMetrics::default()
99        }
100
101        async fn shutdown(&self) -> Result<()> {
102            Ok(())
103        }
104    }
105}
106
107#[cfg(not(feature = "wgpu"))]
108pub use stub::WgpuRuntime;
109
110/// Check if WebGPU is available at runtime.
111pub fn is_wgpu_available() -> bool {
112    #[cfg(feature = "wgpu")]
113    {
114        // Try to create an instance
115        let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default());
116        !instance
117            .enumerate_adapters(wgpu::Backends::all())
118            .is_empty()
119    }
120    #[cfg(not(feature = "wgpu"))]
121    {
122        false
123    }
124}
125
126/// WGSL shader template for ring kernel.
127pub const RING_KERNEL_WGSL_TEMPLATE: &str = r#"
128// RingKernel WGSL Template
129// Generated by ringkernel-wgpu
130
131// Control block binding
132struct ControlBlock {
133    is_active: u32,
134    should_terminate: u32,
135    has_terminated: u32,
136    _pad1: u32,
137    messages_processed_lo: u32,
138    messages_processed_hi: u32,
139    messages_in_flight_lo: u32,
140    messages_in_flight_hi: u32,
141    input_head_lo: u32,
142    input_head_hi: u32,
143    input_tail_lo: u32,
144    input_tail_hi: u32,
145    output_head_lo: u32,
146    output_head_hi: u32,
147    output_tail_lo: u32,
148    output_tail_hi: u32,
149    input_capacity: u32,
150    output_capacity: u32,
151    input_mask: u32,
152    output_mask: u32,
153    // HLC state (split for WGSL u32 limitation)
154    hlc_physical_lo: u32,
155    hlc_physical_hi: u32,
156    hlc_logical_lo: u32,
157    hlc_logical_hi: u32,
158    last_error: u32,
159    error_count: u32,
160}
161
162@group(0) @binding(0) var<storage, read_write> control: ControlBlock;
163@group(0) @binding(1) var<storage, read_write> input_queue: array<u32>;
164@group(0) @binding(2) var<storage, read_write> output_queue: array<u32>;
165
166// Thread identification
167var<private> thread_id: u32;
168var<private> workgroup_id: u32;
169
170@compute @workgroup_size(256)
171fn main(@builtin(global_invocation_id) global_id: vec3<u32>,
172        @builtin(workgroup_id) wg_id: vec3<u32>,
173        @builtin(local_invocation_id) local_id: vec3<u32>) {
174    thread_id = local_id.x;
175    workgroup_id = wg_id.x;
176
177    // Check if kernel should process
178    if (control.is_active == 0u) {
179        return;
180    }
181
182    // User kernel code will be inserted here
183    // USER_KERNEL_CODE
184
185    // Update message counter (simplified without 64-bit atomics)
186    if (thread_id == 0u) {
187        control.messages_processed_lo = control.messages_processed_lo + 1u;
188        if (control.messages_processed_lo == 0u) {
189            control.messages_processed_hi = control.messages_processed_hi + 1u;
190        }
191    }
192}
193"#;