1#![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#[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 pub struct WgpuRuntime;
65
66 impl WgpuRuntime {
67 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
110pub fn is_wgpu_available() -> bool {
112 #[cfg(feature = "wgpu")]
113 {
114 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
126pub 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"#;