ruda_driver_wgpu/
runtime.rs1use crate::{
2 AutoCompiler, AutoGraphicsApi, GraphicsApi, WgpuDevice, backend, execution::WgpuServer,
3 contiguous_strides,
4};
5use ruda_core::device::{Device, DeviceService};
6use ruda_core::{future, profile::TimingMethod};
7use ruda_kernel::dsl::device::{DeviceId, ServerUtilitiesHandle};
8use ruda_kernel::dsl::server::ServerUtilities;
9use ruda_kernel::dsl::zspace::{Shape, Strides};
10use ruda_kernel::dsl::{Runtime, ir::TargetProperties};
11use ruda_core::ir::{DeviceProperties, HardwareProperties, MemoryDeviceProperties};
12use ruda::runtime::allocator::ContiguousMemoryLayoutPolicy;
13#[cfg(not(feature = "vulkan-validate"))]
14use ruda::runtime::logging::ProfileLevel;
15pub use ruda::runtime::memory_management::MemoryConfiguration;
16use ruda::runtime::{client::ComputeClient, logging::ServerLogger};
17use wgpu::{InstanceFlags, RequestAdapterOptions};
18
19#[derive(Debug, Clone)]
23pub struct WgpuRuntime;
24
25impl Runtime for WgpuRuntime {
26 type Compiler = AutoCompiler;
27 type Server = WgpuServer;
28 type Device = WgpuDevice;
29
30 fn client(device: &Self::Device) -> ComputeClient<Self> {
31 ComputeClient::load(device)
32 }
33
34 fn name(client: &ComputeClient<Self>) -> &'static str {
35 match client.info() {
36 wgpu::Backend::Vulkan => {
37 #[cfg(feature = "spirv")]
38 return "wgpu<spirv>";
39
40 #[cfg(not(feature = "spirv"))]
41 return "wgpu<wgsl>";
42 }
43 wgpu::Backend::Metal => {
44 #[cfg(feature = "msl")]
45 return "wgpu<msl>";
46
47 #[cfg(not(feature = "msl"))]
48 return "wgpu<wgsl>";
49 }
50 _ => "wgpu<wgsl>",
51 }
52 }
53
54 fn max_ruda_count() -> (u32, u32, u32) {
55 let max_dim = u16::MAX as u32;
56 (max_dim, max_dim, max_dim)
57 }
58
59 fn can_read_tensor(shape: &Shape, strides: &Strides) -> bool {
60 if shape.is_empty() {
61 return true;
62 }
63
64 for (&expected, &stride) in contiguous_strides(shape).iter().zip(strides.iter()) {
65 if expected != stride {
66 return false;
67 }
68 }
69
70 true
71 }
72
73 fn target_properties() -> TargetProperties {
74 TargetProperties {
75 mma: Default::default(),
77 }
78 }
79
80 fn enumerate_devices(type_id: u16, info: &wgpu::Backend) -> Vec<DeviceId> {
81 #[cfg(target_family = "wasm")]
82 {
83 let _ = type_id;
84 let _ = info;
85 vec![DeviceId::new(0, 0)]
87 }
88
89 #[cfg(not(target_family = "wasm"))]
90 {
91 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
92 backends: wgpu::Backends::all(),
93 ..wgpu::InstanceDescriptor::new_without_display_handle()
94 });
95
96 let adapters = enumerate_all_adapters(instance, *info);
97 adapters
98 .into_iter()
99 .filter(|adapter| {
100 if type_id == 4 {
102 return true;
103 }
104
105 let device_type = adapter.get_info().device_type;
106
107 let adapter_type_id = match device_type {
108 wgpu::DeviceType::Other => 4,
109 wgpu::DeviceType::IntegratedGpu => 1,
110 wgpu::DeviceType::DiscreteGpu => 0,
111 wgpu::DeviceType::VirtualGpu => 2,
112 wgpu::DeviceType::Cpu => 3,
113 };
114
115 adapter_type_id == type_id
116 })
117 .enumerate()
118 .map(|(index, adapter)| match adapter.get_info().device_type {
119 wgpu::DeviceType::DiscreteGpu => DeviceId::new(0, index as u16),
120 wgpu::DeviceType::IntegratedGpu => DeviceId::new(1, index as u16),
121 wgpu::DeviceType::VirtualGpu => DeviceId::new(2, index as u16),
122 wgpu::DeviceType::Cpu => DeviceId::new(3, 0),
123 wgpu::DeviceType::Other => DeviceId::new(4, 0),
124 })
125 .collect()
126 }
127 }
128
129 fn enumerate_all_devices(info: &wgpu::Backend) -> Vec<DeviceId> {
130 #[cfg(target_family = "wasm")]
131 {
132 let _ = info;
133 vec![DeviceId::new(0, 0)]
135 }
136
137 #[cfg(not(target_family = "wasm"))]
138 {
139 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
140 backends: wgpu::Backends::all(),
141 ..wgpu::InstanceDescriptor::new_without_display_handle()
142 });
143 let adapters = enumerate_all_adapters(instance, *info);
144 adapters
145 .into_iter()
146 .enumerate()
147 .map(|(index, adapter)| match adapter.get_info().device_type {
148 wgpu::DeviceType::DiscreteGpu => DeviceId::new(0, index as u16),
149 wgpu::DeviceType::IntegratedGpu => DeviceId::new(1, index as u16),
150 wgpu::DeviceType::VirtualGpu => DeviceId::new(2, index as u16),
151 wgpu::DeviceType::Cpu => DeviceId::new(3, 0),
152 wgpu::DeviceType::Other => DeviceId::new(4, 0),
153 })
154 .collect()
155 }
156 }
157}
158
159#[cfg(not(target_family = "wasm"))]
160fn enumerate_all_adapters(instance: wgpu::Instance, backend: wgpu::Backend) -> Vec<wgpu::Adapter> {
161 ruda_core::future::block_on(instance.enumerate_adapters(backend.into()))
163}
164
165pub struct RuntimeOptions {
167 pub tasks_max: usize,
169 pub memory_config: MemoryConfiguration,
171}
172
173impl Default for RuntimeOptions {
174 fn default() -> Self {
175 #[cfg(test)]
176 const DEFAULT_MAX_TASKS: usize = 32;
177 #[cfg(not(test))]
178 const DEFAULT_MAX_TASKS: usize = 32;
179
180 let tasks_max = match std::env::var("RUDA_WGPU_MAX_TASKS") {
181 Ok(value) => value
182 .parse::<usize>()
183 .expect("RUDA_WGPU_MAX_TASKS should be a positive integer."),
184 Err(_) => DEFAULT_MAX_TASKS,
185 };
186
187 Self {
188 tasks_max,
189 memory_config: MemoryConfiguration::default(),
190 }
191 }
192}
193
194mod adapters;
195mod device_service;
196mod setup;
197
198pub use setup::{WgpuSetup, init_device, init_setup, init_setup_async};
199pub(crate) use setup::create_setup_for_device;
200pub(crate) use device_service::create_server;