pub mod agent_engine;
pub mod capacity;
mod contracts;
pub mod fault;
pub mod grid_engine;
pub mod limits;
pub mod primitives;
pub mod sim_thread;
#[cfg(not(target_arch = "wasm32"))]
pub mod stepping;
pub mod timing;
pub mod view;
#[cfg(test)]
mod tests;
pub use agent_engine::GpuAgentState;
pub use capacity::Demand;
pub use grid_engine::GpuGridState;
pub use limits::GpuNeeds;
pub use primitives::readback::StatsPoll;
pub use primitives::spatial_hash::{GpuSpatialHash, HashGrid};
pub use sim_thread::{GpuSimState, GpuStats};
pub use view::agents::GpuAgents;
pub use view::display::{DisplayTarget, GpuDisplay};
pub use wgpu;
#[cfg(test)]
use tests::support::headless_context;
pub use sim_thread::GpuSimThread;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::fault::{Fault, FaultSink};
use crate::runtime_info::RuntimeInfo;
pub const MAX_STEPS_PER_SUBMISSION: u32 = 64;
#[derive(Debug, Clone)]
pub struct GpuContext {
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub target_format: wgpu::TextureFormat,
pub faults: FaultSink,
lost: Arc<AtomicBool>,
runtime_info: Option<Arc<RuntimeInfo>>,
}
impl GpuContext {
pub fn new(
device: wgpu::Device,
queue: wgpu::Queue,
target_format: wgpu::TextureFormat,
faults: FaultSink,
) -> Self {
let sink = faults.clone();
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
let sink = send_wrapper::SendWrapper::new(sink);
device.on_uncaptured_error(std::sync::Arc::new(move |error: wgpu::Error| {
log::error!("unhandled GPU error: {error}");
sink.set_once(Fault::device("running on the GPU", error));
}));
let lost = Arc::new(AtomicBool::new(false));
let callback_lost = Arc::clone(&lost);
device.set_device_lost_callback(move |reason, message| {
log::error!("GPU device lost ({reason:?}): {message}");
callback_lost.store(true, Ordering::Release);
});
Self {
device,
queue,
target_format,
faults,
lost,
runtime_info: None,
}
}
pub fn with_runtime_info(self, info: RuntimeInfo) -> Self {
Self {
runtime_info: Some(Arc::new(info)),
..self
}
}
pub fn runtime_info(&self) -> Option<&RuntimeInfo> {
self.runtime_info.as_deref()
}
pub fn is_lost(&self) -> bool {
self.lost.load(Ordering::Acquire)
}
}