use vyre_driver::error::Result;
#[inline]
pub fn compile_compute_pipeline(
device: &wgpu::Device,
label: &str,
wgsl_source: &str,
entry_point: &str,
) -> Result<wgpu::ComputePipeline> {
compile_compute_pipeline_with_layout(device, label, wgsl_source, entry_point, None)
}
#[inline]
pub fn compile_compute_pipeline_with_layout(
device: &wgpu::Device,
label: &str,
wgsl_source: &str,
entry_point: &str,
layout: Option<&wgpu::PipelineLayout>,
) -> Result<wgpu::ComputePipeline> {
super::dump_wgsl_if_requested(label, wgsl_source).map_err(|error| {
vyre_driver::error::Error::Gpu {
message: format!(
"failed to dump WGSL for `{label}`: {error}. Fix: set VYRE_DUMP_WGSL to a writable directory or unset it"
),
}
})?;
let driver_cache = if device.features().contains(wgpu::Features::PIPELINE_CACHE) {
Some(driver_pipeline_cache(device, label)?)
} else {
None
};
device.push_error_scope(wgpu::ErrorFilter::Validation);
let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some(label),
source: wgpu::ShaderSource::Wgsl(wgsl_source.into()),
});
let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some(label),
layout,
module: &module,
entry_point: Some(entry_point),
compilation_options: wgpu::PipelineCompilationOptions::default(),
cache: driver_cache.as_ref(),
});
if let Some(error) =
crate::runtime::device::pop_error_scope_now(device).map_err(|message| {
vyre_driver::error::Error::Gpu {
message: format!("WGSL compute pipeline `{label}` validation did not complete without a host wait: {message}"),
}
})?
{
return Err(vyre_driver::error::Error::Gpu {
message: format!(
"WGSL compute pipeline `{label}` failed validation: {error}. Fix: validate the lowered WGSL and adapter limits before compiling."
),
});
}
Ok(pipeline)
}
fn driver_pipeline_cache(device: &wgpu::Device, _label: &str) -> Result<wgpu::PipelineCache> {
use dashmap::DashMap;
use std::sync::LazyLock;
static DRIVER_CACHES: LazyLock<DashMap<wgpu::Device, wgpu::PipelineCache>> =
LazyLock::new(DashMap::new);
if let Some(cache) = DRIVER_CACHES.get(device) {
return Ok(cache.clone());
}
let cache = {
#[allow(unsafe_code)]
unsafe {
device.create_pipeline_cache(&wgpu::PipelineCacheDescriptor {
label: Some("vyre wgpu pipeline cache"),
data: None,
fallback: false,
})
}
};
DRIVER_CACHES.insert(device.clone(), cache.clone());
Ok(cache)
}