cubecl_wgpu/compute/
storage.rs1use cubecl_core::server::IoError;
2use cubecl_environment::backtrace::BackTrace;
3use cubecl_environment::collections::HashMap;
4use cubecl_server::storage::{ComputeStorage, StorageHandle, StorageId, StorageUtilization};
5use std::{num::NonZeroU64, ptr::NonNull};
6use wgpu::BufferUsages;
7
8const MIN_BUFFER_SIZE: u64 = 32;
12
13pub struct WgpuStorage {
15 memory: HashMap<StorageId, WgpuMemory>,
16 allocated: u64,
18 device: wgpu::Device,
19 buffer_usages: BufferUsages,
20 mem_alignment: usize,
21 #[allow(unused, reason = "keep it simple")]
22 vk_storage: bool,
23}
24
25impl core::fmt::Debug for WgpuStorage {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.write_str(format!("WgpuStorage {{ device: {:?} }}", self.device).as_str())
28 }
29}
30
31#[derive(Debug, Clone, Copy)]
33pub(crate) struct HostPtr(pub(crate) NonNull<u8>);
34
35unsafe impl Send for HostPtr {}
37unsafe impl Sync for HostPtr {}
38
39#[derive(new, Debug, Clone)]
41pub struct WgpuResource {
42 pub buffer: wgpu::Buffer,
44 pub address: Option<NonZeroU64>,
46 #[new(default)]
48 pub(crate) host_ptr: Option<HostPtr>,
49 pub offset: u64,
51 pub size: u64,
57}
58
59#[derive(new, Debug)]
61pub struct WgpuMemory {
62 pub buffer: wgpu::Buffer,
64 pub address: Option<NonZeroU64>,
66 #[new(default)]
68 pub(crate) host_ptr: Option<HostPtr>,
69}
70
71impl WgpuResource {
72 pub fn as_wgpu_bind_resource(&self) -> wgpu::BindingResource<'_> {
74 let size = NonZeroU64::new(self.size.next_multiple_of(4));
84
85 let binding = wgpu::BufferBinding {
86 buffer: &self.buffer,
87 offset: self.offset,
88 size,
89 };
90 wgpu::BindingResource::Buffer(binding)
91 }
92}
93
94impl WgpuStorage {
96 pub fn new(
98 mem_alignment: usize,
99 device: wgpu::Device,
100 usages: BufferUsages,
101 vk_storage: bool,
102 ) -> Self {
103 Self {
104 memory: HashMap::new(),
105 allocated: 0,
106 device,
107 buffer_usages: usages,
108 mem_alignment,
109 vk_storage,
110 }
111 }
112}
113
114impl ComputeStorage for WgpuStorage {
115 type Resource = WgpuResource;
116
117 fn alignment(&self) -> usize {
118 self.mem_alignment
119 }
120
121 fn get(&mut self, handle: &StorageHandle) -> Result<Self::Resource, IoError> {
122 let memory = self
123 .memory
124 .get(&handle.id)
125 .ok_or_else(|| IoError::StorageHandleNotFound {
126 reason: format!("{} in the wgpu buffer storage", handle.id).into(),
127 backtrace: BackTrace::capture(),
128 })?;
129 Ok(WgpuResource {
130 host_ptr: memory.host_ptr,
131 ..WgpuResource::new(
132 memory.buffer.clone(),
133 memory.address,
134 handle.offset(),
135 handle.size(),
136 )
137 })
138 }
139
140 #[cfg_attr(
141 feature = "tracing",
142 tracing::instrument(level = "trace", skip(self, size))
143 )]
144 fn alloc(&mut self, size: u64) -> Result<StorageHandle, IoError> {
145 let id = StorageId::new();
146
147 let alloc_size = size.max(MIN_BUFFER_SIZE);
148
149 let memory = self.create_buffer(&wgpu::BufferDescriptor {
150 label: None,
151 size: alloc_size,
152 usage: self.buffer_usages,
153 mapped_at_creation: false,
154 })?;
155
156 self.memory.insert(id, memory);
157 self.allocated += alloc_size;
158 Ok(StorageHandle::new(
159 id,
160 StorageUtilization { offset: 0, size },
161 ))
162 }
163
164 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip(self)))]
165 fn dealloc(&mut self, id: StorageId) {
166 if let Some(memory) = self.memory.remove(&id) {
167 self.allocated -= memory.buffer.size();
168 }
169 }
170
171 fn flush(&mut self) {
172 }
174
175 fn bytes_allocated(&self) -> u64 {
176 self.allocated
177 }
178}
179
180impl WgpuStorage {
181 #[cfg(feature = "spirv")]
182 fn create_buffer(&self, desc: &wgpu::BufferDescriptor<'_>) -> Result<WgpuMemory, IoError> {
183 if self.vk_storage {
184 crate::backend::vulkan::create_storage_buffer(&self.device, desc)
190 } else {
191 Ok(WgpuMemory::new(self.device.create_buffer(desc), None))
192 }
193 }
194
195 #[cfg(not(feature = "spirv"))]
196 fn create_buffer(&self, desc: &wgpu::BufferDescriptor<'_>) -> Result<WgpuMemory, IoError> {
197 Ok(WgpuMemory::new(self.device.create_buffer(desc), None))
198 }
199}