use crate::webgpu::{BackendCapabilities, ComputeError, MemoryStats};
use crate::ActivationFunction;
use num_traits::Float;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex, RwLock};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_futures::JsFuture;
#[cfg(target_arch = "wasm32")]
use js_sys::{Array, Float32Array, Float64Array, Object, Promise, Uint8Array};
#[cfg(target_arch = "wasm32")]
use web_sys::{
console, BroadcastChannel, Document, Element, HtmlCanvasElement, MessageChannel, MessagePort,
Navigator, Performance, ServiceWorkerContainer, Window, Worker,
};
#[cfg(all(target_arch = "wasm32", feature = "webgpu"))]
use web_sys::{
Gpu, GpuAdapter, GpuBindGroup, GpuBuffer, GpuCanvasContext, GpuCommandEncoder,
GpuComputePassEncoder, GpuComputePipeline, GpuDevice, GpuQueue, GpuTexture,
};
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub struct WasmGpuBridge {
inner: Arc<RwLock<WasmGpuBridgeInner>>,
}
#[cfg(target_arch = "wasm32")]
pub struct WasmGpuBridgeInner {
gpu_context: Option<WebGpuContext>,
memory_manager: WasmMemoryManager,
performance_monitor: WasmPerformanceMonitor,
browser_compatibility: BrowserCompatibility,
cross_origin_manager: CrossOriginManager,
}
#[cfg(target_arch = "wasm32")]
pub struct WebGpuContext {
gpu: Gpu,
adapter: GpuAdapter,
device: GpuDevice,
queue: GpuQueue,
canvas_context: Option<GpuCanvasContext>,
capabilities: WebGpuCapabilities,
feature_level: WebGpuFeatureLevel,
}
#[cfg(target_arch = "wasm32")]
pub struct WasmMemoryManager {
shared_buffers: HashMap<String, SharedBuffer>,
memory_pools: Vec<MemoryPool>,
js_heap_monitor: JsHeapMonitor,
gc_coordinator: GcCoordinator,
zero_copy_regions: Vec<ZeroCopyRegion>,
}
#[cfg(target_arch = "wasm32")]
pub struct WasmPerformanceMonitor {
performance_api: Performance,
gpu_timing_queries: Vec<GpuTimingQuery>,
memory_usage_tracker: MemoryUsageTracker,
frame_rate_monitor: Option<FrameRateMonitor>,
battery_monitor: Option<BatteryMonitor>,
}
#[cfg(target_arch = "wasm32")]
pub struct BrowserCompatibility {
browser_type: BrowserType,
webgpu_support_level: WebGpuSupportLevel,
fallback_strategies: Vec<FallbackStrategy>,
polyfill_manager: PolyfillManager,
version_specific_optimizations: HashMap<String, OptimizationSet>,
}
#[cfg(target_arch = "wasm32")]
pub struct CrossOriginManager {
cors_policies: CorsPolicy,
csp_compliance: CspCompliance,
shared_array_buffer_support: bool,
worker_security_context: WorkerSecurityContext,
}
#[cfg(target_arch = "wasm32")]
pub struct SharedBuffer {
js_buffer: Float32Array,
rust_view: Vec<f32>,
is_shared: bool,
last_sync: f64,
sync_direction: SyncDirection,
}
#[cfg(target_arch = "wasm32")]
pub struct MemoryPool {
pool_id: String,
block_size: usize,
total_blocks: usize,
free_blocks: Vec<usize>,
allocated_blocks: HashMap<String, usize>,
pool_type: PoolType,
}
#[cfg(target_arch = "wasm32")]
pub struct JsHeapMonitor {
memory_api: Option<js_sys::Object>,
last_gc_time: f64,
heap_size_history: Vec<(f64, usize)>,
pressure_threshold: usize,
gc_frequency_ms: f64,
}
#[cfg(target_arch = "wasm32")]
pub struct GcCoordinator {
auto_gc_enabled: bool,
gc_pressure_threshold: f64,
manual_gc_trigger: Option<js_sys::Function>,
gc_timing_strategy: GcTimingStrategy,
}
#[cfg(target_arch = "wasm32")]
pub struct ZeroCopyRegion {
js_array_buffer: js_sys::ArrayBuffer,
rust_slice: *mut f32,
size_bytes: usize,
is_mutable: bool,
reference_count: usize,
}
#[cfg(target_arch = "wasm32")]
pub struct GpuTimingQuery {
query_set: web_sys::GpuQuerySet,
query_buffer: GpuBuffer,
query_index: u32,
timestamp_period: f64,
}
#[cfg(target_arch = "wasm32")]
pub struct MemoryUsageTracker {
performance_memory: Option<js_sys::Object>,
heap_snapshots: Vec<HeapSnapshot>,
wasm_memory_usage: usize,
js_memory_usage: usize,
gpu_memory_usage: usize,
}
#[cfg(target_arch = "wasm32")]
pub struct FrameRateMonitor {
animation_frame_id: Option<i32>,
frame_times: Vec<f64>,
target_fps: f64,
performance_budget: f64,
}
#[cfg(target_arch = "wasm32")]
pub struct BatteryMonitor {
battery_api: Option<js_sys::Object>,
charging_state: bool,
battery_level: f64,
power_optimization_mode: PowerOptimizationMode,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum BrowserType {
Chrome,
Firefox,
Safari,
Edge,
Unknown(String),
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum WebGpuSupportLevel {
Full,
Partial,
Experimental,
None,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum WebGpuFeatureLevel {
WebGpu1_0,
WebGpu2_0,
Experimental,
Fallback,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct WebGpuCapabilities {
max_texture_dimension_1d: u32,
max_texture_dimension_2d: u32,
max_texture_dimension_3d: u32,
max_buffer_size: u64,
max_compute_workgroup_size_x: u32,
max_compute_workgroup_size_y: u32,
max_compute_workgroup_size_z: u32,
max_compute_workgroups_per_dimension: u32,
max_compute_invocations_per_workgroup: u32,
supports_timestamp_queries: bool,
supports_pipeline_statistics: bool,
supports_storage_textures: bool,
adapter_info: AdapterInfo,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct AdapterInfo {
vendor: String,
architecture: String,
device: String,
description: String,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum SyncDirection {
JsToRust,
RustToJs,
Bidirectional,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum PoolType {
Vertex,
Index,
Uniform,
Storage,
Texture,
Staging,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum GcTimingStrategy {
Immediate,
Deferred,
FrameBased,
IdleBased,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct WebTask {
task_id: String,
task_type: String,
data: js_sys::Object,
priority: u32,
timeout_ms: Option<u32>,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct WorkerPerformanceMetrics {
tasks_completed: u32,
average_execution_time_ms: f64,
error_rate: f64,
memory_usage_mb: f64,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum CacheStrategy {
CacheFirst,
NetworkFirst,
CacheOnly,
NetworkOnly,
StaleWhileRevalidate,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct OfflineCapabilities {
can_run_offline: bool,
cached_models: Vec<String>,
offline_storage_mb: u64,
sync_strategies: Vec<SyncStrategy>,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum SyncStrategy {
Immediate,
Periodic,
OnConnection,
Manual,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct BackgroundSyncManager {
sync_registrations: Vec<String>,
pending_syncs: Vec<PendingSync>,
retry_strategy: RetryStrategy,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct PendingSync {
sync_id: String,
data: js_sys::Object,
retry_count: u32,
next_retry: f64,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum RetryStrategy {
Linear,
Exponential,
Fibonacci,
Custom(js_sys::Function),
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct TabInfo {
tab_id: String,
last_heartbeat: f64,
capabilities: TabCapabilities,
role: TabRole,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct TabCapabilities {
has_webgpu: bool,
memory_limit_mb: u64,
is_focused: bool,
battery_saver_mode: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum TabRole {
Leader,
Worker,
Observer,
Backup,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum CoordinationProtocol {
LeaderFollower,
Distributed,
Hierarchical,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct TabConflictResolver {
resolution_strategy: ConflictResolutionStrategy,
timeout_ms: u32,
fallback_to_local: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum ConflictResolutionStrategy {
Timestamp,
Priority,
Voting,
Arbitrary,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct StorageQuota {
total_quota_mb: u64,
used_quota_mb: u64,
can_request_persistent: bool,
estimate_api_available: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct WebMessage {
message_id: String,
from: String,
to: String,
message_type: String,
data: js_sys::Object,
timestamp: f64,
priority: u32,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct DeliveryGuarantees {
retry_count: u32,
timeout_ms: u32,
require_acknowledgment: bool,
ordering_required: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct HeapSnapshot {
timestamp: f64,
total_heap_size: usize,
used_heap_size: usize,
heap_size_limit: usize,
number_of_native_contexts: u32,
number_of_detached_contexts: u32,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum PowerOptimizationMode {
HighPerformance,
Balanced,
PowerSaver,
Automatic,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct FallbackStrategy {
condition: FallbackCondition,
target_backend: String,
performance_threshold: f64,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, PartialEq)]
pub enum FallbackCondition {
WebGpuUnavailable,
PerformanceBelowThreshold,
MemoryPressure,
BatteryLow,
ThermalThrottling,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct PolyfillManager {
active_polyfills: Vec<String>,
polyfill_registry: HashMap<String, js_sys::Function>,
feature_detection: FeatureDetection,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct FeatureDetection {
webgpu_available: bool,
shared_array_buffer_available: bool,
bigint_available: bool,
atomics_available: bool,
wasm_simd_available: bool,
wasm_threads_available: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct OptimizationSet {
memory_optimizations: Vec<String>,
compute_optimizations: Vec<String>,
rendering_optimizations: Vec<String>,
power_optimizations: Vec<String>,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct CorsPolicy {
allowed_origins: Vec<String>,
credentials_required: bool,
max_age: u32,
allowed_methods: Vec<String>,
allowed_headers: Vec<String>,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct CspCompliance {
script_src_policy: String,
worker_src_policy: String,
connect_src_policy: String,
wasm_eval_allowed: bool,
unsafe_eval_allowed: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone)]
pub struct WorkerSecurityContext {
same_origin_policy: bool,
cors_enabled: bool,
trusted_origins: Vec<String>,
message_integrity_check: bool,
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl WasmGpuBridge {
#[wasm_bindgen(constructor)]
pub fn new() -> Result<WasmGpuBridge, JsValue> {
console::log_1(&"Initializing WASM GPU Bridge".into());
let inner = WasmGpuBridgeInner {
gpu_context: None,
memory_manager: WasmMemoryManager::new()?,
performance_monitor: WasmPerformanceMonitor::new()?,
browser_compatibility: BrowserCompatibility::detect()?,
cross_origin_manager: CrossOriginManager::new()?,
};
Ok(WasmGpuBridge {
inner: Arc::new(RwLock::new(inner)),
})
}
#[wasm_bindgen]
#[cfg(feature = "webgpu")]
pub async fn initialize_webgpu(&self, canvas_id: Option<String>) -> Result<(), JsValue> {
let window = web_sys::window().ok_or("No window object")?;
let navigator = window.navigator();
let gpu = js_sys::Reflect::get(&navigator.into(), &"gpu".into())
.map_err(|_| "WebGPU not available")?;
let gpu: Gpu = gpu.into();
let adapter_options = web_sys::GpuRequestAdapterOptions::new();
adapter_options.set_power_preference(web_sys::GpuPowerPreference::HighPerformance);
let adapter_promise = gpu.request_adapter_with_options(&adapter_options);
let adapter_result = JsFuture::from(adapter_promise).await?;
let adapter: GpuAdapter = adapter_result.into();
let device_descriptor = web_sys::GpuDeviceDescriptor::new();
device_descriptor.set_label("rfann WebGPU Device");
let device_promise = adapter.request_device_with_descriptor(&device_descriptor);
let device_result = JsFuture::from(device_promise).await?;
let device: GpuDevice = device_result.into();
let queue = device.queue();
let canvas_context = if let Some(canvas_id) = canvas_id {
let document = window.document().ok_or("No document")?;
let canvas = document
.get_element_by_id(&canvas_id)
.ok_or("Canvas not found")?
.dyn_into::<HtmlCanvasElement>()?;
let context = canvas
.get_context("webgpu")?
.ok_or("Failed to get WebGPU context")?
.dyn_into::<GpuCanvasContext>()?;
let config = web_sys::GpuCanvasConfiguration::new(&device, "bgra8unorm");
context.configure(&config);
Some(context)
} else {
None
};
let adapter_info = adapter.info();
let capabilities = self.get_webgpu_capabilities(&adapter, &device).await?;
let gpu_context = WebGpuContext {
gpu,
adapter,
device,
queue,
canvas_context,
capabilities,
feature_level: WebGpuFeatureLevel::WebGpu1_0,
};
{
let mut inner = self.inner.write().unwrap();
inner.gpu_context = Some(gpu_context);
}
console::log_1(&"WebGPU context initialized successfully".into());
Ok(())
}
#[wasm_bindgen]
#[cfg(not(feature = "webgpu"))]
pub async fn initialize_webgpu(&self, _canvas_id: Option<String>) -> Result<(), JsValue> {
console::log_1(&"WebGPU not available, using CPU fallback".into());
Ok(())
}
#[cfg(feature = "webgpu")]
async fn get_webgpu_capabilities(
&self,
adapter: &GpuAdapter,
device: &GpuDevice,
) -> Result<WebGpuCapabilities, JsValue> {
let adapter_info = adapter.info();
let limits = device.limits();
Ok(WebGpuCapabilities {
max_texture_dimension_1d: limits.max_texture_dimension_1d(),
max_texture_dimension_2d: limits.max_texture_dimension_2d(),
max_texture_dimension_3d: limits.max_texture_dimension_3d(),
max_buffer_size: limits.max_buffer_size() as u64,
max_compute_workgroup_size_x: limits.max_compute_workgroup_size_x(),
max_compute_workgroup_size_y: limits.max_compute_workgroup_size_y(),
max_compute_workgroup_size_z: limits.max_compute_workgroup_size_z(),
max_compute_workgroups_per_dimension: limits.max_compute_workgroups_per_dimension(),
max_compute_invocations_per_workgroup: limits.max_compute_invocations_per_workgroup(),
supports_timestamp_queries: device.features().has("timestamp-query"),
supports_pipeline_statistics: device.features().has("pipeline-statistics-query"),
supports_storage_textures: device.features().has("storage-texture"),
adapter_info: AdapterInfo {
vendor: adapter_info.vendor(),
architecture: adapter_info.architecture(),
device: adapter_info.device(),
description: adapter_info.description(),
},
})
}
#[wasm_bindgen]
pub fn create_shared_buffer(&self, name: &str, size: usize) -> Result<(), JsValue> {
let js_buffer = Float32Array::new_with_length(size as u32);
let rust_view = vec![0.0f32; size];
let shared_buffer = SharedBuffer {
js_buffer,
rust_view,
is_shared: true,
last_sync: self.get_current_time(),
sync_direction: SyncDirection::Bidirectional,
};
{
let mut inner = self.inner.write().unwrap();
inner
.memory_manager
.shared_buffers
.insert(name.to_string(), shared_buffer);
}
Ok(())
}
#[wasm_bindgen]
pub fn sync_buffer(&self, name: &str, direction: &str) -> Result<(), JsValue> {
let sync_dir = match direction {
"js_to_rust" => SyncDirection::JsToRust,
"rust_to_js" => SyncDirection::RustToJs,
"bidirectional" => SyncDirection::Bidirectional,
_ => return Err("Invalid sync direction".into()),
};
{
let mut inner = self.inner.write().unwrap();
if let Some(buffer) = inner.memory_manager.shared_buffers.get_mut(name) {
match sync_dir {
SyncDirection::JsToRust => {
for i in 0..buffer.rust_view.len() {
buffer.rust_view[i] = buffer.js_buffer.get_index(i as u32);
}
}
SyncDirection::RustToJs => {
for (i, &value) in buffer.rust_view.iter().enumerate() {
buffer.js_buffer.set_index(i as u32, value);
}
}
SyncDirection::Bidirectional => {
for (i, &value) in buffer.rust_view.iter().enumerate() {
buffer.js_buffer.set_index(i as u32, value);
}
}
}
buffer.last_sync = self.get_current_time();
buffer.sync_direction = sync_dir;
}
}
Ok(())
}
#[wasm_bindgen]
pub async fn gpu_matrix_multiply(
&self,
matrix_a: &str,
matrix_b: &str,
result_buffer: &str,
rows_a: u32,
cols_a: u32,
cols_b: u32,
) -> Result<(), JsValue> {
let inner = self.inner.read().unwrap();
let gpu_context = inner.gpu_context.as_ref().ok_or("WebGPU not initialized")?;
let shader_code = include_str!("shaders/matrix_vector_multiply.wgsl");
let shader_module = gpu_context
.device
.create_shader_module_with_source(&shader_code);
let compute_pipeline = gpu_context.device.create_compute_pipeline(
&web_sys::GpuComputePipelineDescriptor::new(&shader_module, "main"),
);
let buffer_a = inner
.memory_manager
.shared_buffers
.get(matrix_a)
.ok_or("Matrix A buffer not found")?;
let buffer_b = inner
.memory_manager
.shared_buffers
.get(matrix_b)
.ok_or("Matrix B buffer not found")?;
let result_buf = inner
.memory_manager
.shared_buffers
.get(result_buffer)
.ok_or("Result buffer not found")?;
let gpu_buffer_a =
self.create_gpu_buffer_from_js_array(&gpu_context.device, &buffer_a.js_buffer)?;
let gpu_buffer_b =
self.create_gpu_buffer_from_js_array(&gpu_context.device, &buffer_b.js_buffer)?;
let gpu_result_buffer =
self.create_gpu_buffer(&gpu_context.device, (rows_a * cols_b * 4) as u64)?;
let bind_group_layout = compute_pipeline.get_bind_group_layout(0);
let bind_group =
gpu_context
.device
.create_bind_group(&web_sys::GpuBindGroupDescriptor::new(
&bind_group_layout,
&js_sys::Array::of3(&gpu_buffer_a, &gpu_buffer_b, &gpu_result_buffer),
));
let command_encoder = gpu_context.device.create_command_encoder();
let compute_pass = command_encoder.begin_compute_pass();
compute_pass.set_pipeline(&compute_pipeline);
compute_pass.set_bind_group(0, Some(&bind_group));
compute_pass.dispatch_workgroups(
(cols_b + 15) / 16, (rows_a + 15) / 16,
1,
);
compute_pass.end();
let command_buffer = command_encoder.finish();
gpu_context
.queue
.submit(&js_sys::Array::of1(&command_buffer));
console::log_1(&"GPU matrix multiplication completed".into());
Ok(())
}
#[wasm_bindgen]
pub async fn gpu_apply_activation(
&self,
input_buffer: &str,
output_buffer: &str,
activation_type: &str,
steepness: f32,
) -> Result<(), JsValue> {
let inner = self.inner.read().unwrap();
let gpu_context = inner.gpu_context.as_ref().ok_or("WebGPU not initialized")?;
let shader_code = include_str!("shaders/activation_functions.wgsl");
let shader_module = gpu_context
.device
.create_shader_module_with_source(&shader_code);
let compute_pipeline = gpu_context.device.create_compute_pipeline(
&web_sys::GpuComputePipelineDescriptor::new(&shader_module, "apply_activation"),
);
console::log_1(&format!("Applied {} activation function on GPU", activation_type).into());
Ok(())
}
#[wasm_bindgen]
pub fn get_performance_metrics(&self) -> Result<js_sys::Object, JsValue> {
let inner = self.inner.read().unwrap();
let metrics = js_sys::Object::new();
if let Some(ref gpu_context) = inner.gpu_context {
js_sys::Reflect::set(&metrics, &"webgpu_available".into(), &true.into())?;
js_sys::Reflect::set(
&metrics,
&"gpu_vendor".into(),
&gpu_context.capabilities.adapter_info.vendor.into(),
)?;
js_sys::Reflect::set(
&metrics,
&"gpu_device".into(),
&gpu_context.capabilities.adapter_info.device.into(),
)?;
} else {
js_sys::Reflect::set(&metrics, &"webgpu_available".into(), &false.into())?;
}
js_sys::Reflect::set(
&metrics,
&"shared_buffers_count".into(),
&(inner.memory_manager.shared_buffers.len() as u32).into(),
)?;
js_sys::Reflect::set(
&metrics,
&"memory_pools_count".into(),
&(inner.memory_manager.memory_pools.len() as u32).into(),
)?;
js_sys::Reflect::set(
&metrics,
&"browser_type".into(),
&format!("{:?}", inner.browser_compatibility.browser_type).into(),
)?;
js_sys::Reflect::set(
&metrics,
&"webgpu_support_level".into(),
&format!("{:?}", inner.browser_compatibility.webgpu_support_level).into(),
)?;
Ok(metrics)
}
#[wasm_bindgen]
pub fn check_feature_support(&self) -> Result<js_sys::Object, JsValue> {
let features = js_sys::Object::new();
let window = web_sys::window().ok_or("No window object")?;
let navigator = window.navigator();
let webgpu_available = navigator.gpu().is_some();
js_sys::Reflect::set(&features, &"webgpu".into(), &webgpu_available.into())?;
let shared_array_buffer_available = js_sys::global().get("SharedArrayBuffer").is_object();
js_sys::Reflect::set(
&features,
&"shared_array_buffer".into(),
&shared_array_buffer_available.into(),
)?;
let offscreen_canvas_available = js_sys::global().get("OffscreenCanvas").is_object();
js_sys::Reflect::set(
&features,
&"offscreen_canvas".into(),
&offscreen_canvas_available.into(),
)?;
let web_workers_available = js_sys::global().get("Worker").is_object();
js_sys::Reflect::set(
&features,
&"web_workers".into(),
&web_workers_available.into(),
)?;
let service_workers_available = navigator.service_worker().is_some();
js_sys::Reflect::set(
&features,
&"service_workers".into(),
&service_workers_available.into(),
)?;
Ok(features)
}
fn get_current_time(&self) -> f64 {
if let Some(window) = web_sys::window() {
if let Some(performance) = window.performance() {
return performance.now();
}
}
0.0
}
fn create_gpu_buffer_from_js_array(
&self,
device: &GpuDevice,
js_array: &Float32Array,
) -> Result<GpuBuffer, JsValue> {
let size = js_array.length() as u64 * 4; let buffer = device.create_buffer(&web_sys::GpuBufferDescriptor::new(
size,
web_sys::GpuBufferUsage::STORAGE | web_sys::GpuBufferUsage::COPY_DST,
));
let data = js_array.to_vec();
let data_u8: &[u8] =
unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4) };
device
.queue()
.write_buffer_with_u8_array(&buffer, 0, data_u8);
Ok(buffer)
}
fn create_gpu_buffer(&self, device: &GpuDevice, size: u64) -> Result<GpuBuffer, JsValue> {
Ok(device.create_buffer(&web_sys::GpuBufferDescriptor::new(
size,
web_sys::GpuBufferUsage::STORAGE | web_sys::GpuBufferUsage::COPY_SRC,
)))
}
}
#[cfg(target_arch = "wasm32")]
impl WasmMemoryManager {
pub fn new() -> Result<Self, JsValue> {
Ok(Self {
shared_buffers: HashMap::new(),
memory_pools: Vec::new(),
js_heap_monitor: JsHeapMonitor::new()?,
gc_coordinator: GcCoordinator::new()?,
zero_copy_regions: Vec::new(),
})
}
}
#[cfg(target_arch = "wasm32")]
impl WasmPerformanceMonitor {
pub fn new() -> Result<Self, JsValue> {
let window = web_sys::window().ok_or("No window object")?;
let performance = window
.performance()
.ok_or("Performance API not available")?;
Ok(Self {
performance_api: performance,
gpu_timing_queries: Vec::new(),
memory_usage_tracker: MemoryUsageTracker::new()?,
frame_rate_monitor: None,
battery_monitor: None,
})
}
}
#[cfg(target_arch = "wasm32")]
impl BrowserCompatibility {
pub fn detect() -> Result<Self, JsValue> {
let window = web_sys::window().ok_or("No window object")?;
let navigator = window.navigator();
let user_agent = navigator.user_agent()?;
let browser_type = if user_agent.contains("Chrome") {
BrowserType::Chrome
} else if user_agent.contains("Firefox") {
BrowserType::Firefox
} else if user_agent.contains("Safari") && !user_agent.contains("Chrome") {
BrowserType::Safari
} else if user_agent.contains("Edge") {
BrowserType::Edge
} else {
BrowserType::Unknown(user_agent)
};
let webgpu_support_level = if js_sys::Reflect::get(&js_sys::global(), &"navigator".into())
.ok()
.and_then(|nav| js_sys::Reflect::get(&nav, &"gpu".into()).ok())
.map(|gpu| gpu.is_object())
.unwrap_or(false)
{
WebGpuSupportLevel::Full
} else {
WebGpuSupportLevel::None
};
Ok(Self {
browser_type,
webgpu_support_level,
fallback_strategies: Vec::new(),
polyfill_manager: PolyfillManager::new()?,
version_specific_optimizations: HashMap::new(),
})
}
}
#[cfg(target_arch = "wasm32")]
impl CrossOriginManager {
pub fn new() -> Result<Self, JsValue> {
Ok(Self {
cors_policies: CorsPolicy::default(),
csp_compliance: CspCompliance::default(),
shared_array_buffer_support: js_sys::Reflect::has(
&js_sys::global(),
&"SharedArrayBuffer".into(),
)
.unwrap_or(false),
worker_security_context: WorkerSecurityContext::default(),
})
}
}
#[cfg(target_arch = "wasm32")]
impl JsHeapMonitor {
pub fn new() -> Result<Self, JsValue> {
let memory_api = js_sys::Reflect::get(&js_sys::global(), &"performance".into())
.ok()
.and_then(|perf| js_sys::Reflect::get(&perf, &"memory".into()).ok())
.filter(|mem| mem.is_object())
.map(|mem| mem.into());
Ok(Self {
memory_api,
last_gc_time: 0.0,
heap_size_history: Vec::new(),
pressure_threshold: 1024 * 1024 * 100, gc_frequency_ms: 5000.0, })
}
}
#[cfg(target_arch = "wasm32")]
impl GcCoordinator {
pub fn new() -> Result<Self, JsValue> {
Ok(Self {
auto_gc_enabled: true,
gc_pressure_threshold: 0.8, manual_gc_trigger: None,
gc_timing_strategy: GcTimingStrategy::IdleBased,
})
}
}
#[cfg(target_arch = "wasm32")]
impl MemoryUsageTracker {
pub fn new() -> Result<Self, JsValue> {
let performance_memory = js_sys::Reflect::get(&js_sys::global(), &"performance".into())
.ok()
.and_then(|perf| js_sys::Reflect::get(&perf, &"memory".into()).ok())
.filter(|mem| mem.is_object())
.map(|mem| mem.into());
Ok(Self {
performance_memory,
heap_snapshots: Vec::new(),
wasm_memory_usage: 0,
js_memory_usage: 0,
gpu_memory_usage: 0,
})
}
}
#[cfg(target_arch = "wasm32")]
impl PolyfillManager {
pub fn new() -> Result<Self, JsValue> {
Ok(Self {
active_polyfills: Vec::new(),
polyfill_registry: HashMap::new(),
feature_detection: FeatureDetection {
webgpu_available: js_sys::Reflect::get(&js_sys::global(), &"navigator".into())
.ok()
.and_then(|nav| js_sys::Reflect::get(&nav, &"gpu".into()).ok())
.map(|gpu| gpu.is_object())
.unwrap_or(false),
shared_array_buffer_available: js_sys::Reflect::has(
&js_sys::global(),
&"SharedArrayBuffer".into(),
)
.unwrap_or(false),
bigint_available: js_sys::Reflect::has(&js_sys::global(), &"BigInt".into())
.unwrap_or(false),
atomics_available: js_sys::Reflect::has(&js_sys::global(), &"Atomics".into())
.unwrap_or(false),
wasm_simd_available: false, wasm_threads_available: false, },
})
}
}
#[cfg(target_arch = "wasm32")]
impl Default for CorsPolicy {
fn default() -> Self {
Self {
allowed_origins: vec!["*".to_string()],
credentials_required: false,
max_age: 86400, allowed_methods: vec!["GET".to_string(), "POST".to_string()],
allowed_headers: vec!["Content-Type".to_string()],
}
}
}
#[cfg(target_arch = "wasm32")]
impl Default for CspCompliance {
fn default() -> Self {
Self {
script_src_policy: "'self'".to_string(),
worker_src_policy: "'self'".to_string(),
connect_src_policy: "'self'".to_string(),
wasm_eval_allowed: true,
unsafe_eval_allowed: false,
}
}
}
#[cfg(target_arch = "wasm32")]
impl Default for WorkerSecurityContext {
fn default() -> Self {
Self {
same_origin_policy: true,
cors_enabled: false,
trusted_origins: Vec::new(),
message_integrity_check: false,
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub struct WasmGpuBridge;
#[cfg(not(target_arch = "wasm32"))]
impl WasmGpuBridge {
pub fn new() -> Result<Self, String> {
Err("WASM GPU Bridge is only available in WebAssembly builds".to_string())
}
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(start)]
pub fn main() {
console_error_panic_hook::set_once();
console::log_1(&"rfann WASM GPU Bridge initialized".into());
}