1use crate::pool::BufferPool;
4use crate::WgpuContext;
5use std::sync::Arc;
6use wgpu::{util::DeviceExt, Buffer};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum DType {
11 #[default]
13 FP32,
14 FP16,
16}
17
18impl DType {
19 pub fn size_bytes(&self) -> usize {
21 match self {
22 DType::FP32 => 4,
23 DType::FP16 => 2,
24 }
25 }
26}
27
28#[derive(Debug, Clone)]
33pub struct UnifiedTensor {
34 data: Arc<TensorData>,
35 pub shape: Vec<usize>,
37 pub dtype: DType, }
40
41#[derive(Debug)]
42struct TensorData {
43 buffer: Arc<Buffer>,
44 size_in_bytes: u64,
45 pool: Option<Arc<BufferPool>>,
46}
47
48impl Drop for TensorData {
49 fn drop(&mut self) {
50 if let Some(pool) = &self.pool {
51 pool.return_buffer(self.size_in_bytes, self.buffer.clone());
52 }
53 }
54}
55
56impl UnifiedTensor {
57 pub fn buffer(&self) -> &Buffer {
59 &self.data.buffer
60 }
61
62 pub fn size_in_bytes(&self) -> u64 {
64 self.data.size_in_bytes
65 }
66
67 pub fn write_data(&self, context: &WgpuContext, data: &[u8]) {
69 context.queue.write_buffer(self.buffer(), 0, data);
70 }
71}
72
73impl UnifiedTensor {
74 pub fn new(context: &WgpuContext, data: &[f32], shape: &[usize]) -> Self {
76 let size_in_bytes = (data.len() * 4) as u64;
77 let buffer = context
78 .device
79 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
80 label: Some("Tensor"),
81 contents: bytemuck::cast_slice(data),
82 usage: wgpu::BufferUsages::STORAGE
83 | wgpu::BufferUsages::COPY_DST
84 | wgpu::BufferUsages::COPY_SRC,
85 });
86 Self {
87 data: Arc::new(TensorData {
88 buffer: Arc::new(buffer),
89 size_in_bytes,
90 pool: None,
91 }),
92 shape: shape.to_vec(),
93 dtype: DType::FP32,
94 }
95 }
96
97 pub fn empty(context: &WgpuContext, shape: &[usize]) -> Self {
99 Self::empty_with_dtype(context, shape, DType::FP32)
100 }
101
102 pub fn empty_with_dtype(context: &WgpuContext, shape: &[usize], dtype: DType) -> Self {
104 let size_in_bytes = (shape.iter().product::<usize>() * dtype.size_bytes()) as u64;
105 let buffer = context.pool.get(&context.device, size_in_bytes);
106 Self {
107 data: Arc::new(TensorData {
108 buffer,
109 size_in_bytes,
110 pool: Some(context.pool.clone()),
111 }),
112 shape: shape.to_vec(),
113 dtype,
114 }
115 }
116
117 pub fn zeros(context: &WgpuContext, shape: &[usize]) -> Self {
119 let size = shape.iter().product::<usize>();
120 let data = vec![0.0f32; size];
121 Self::new(context, &data, shape)
122 }
123
124 pub fn from_bytes(context: &WgpuContext, data: &[u8], shape: &[usize]) -> Self {
126 Self::from_bytes_with_dtype(context, data, shape, DType::FP32)
127 }
128
129 pub fn from_bytes_with_dtype(
131 context: &WgpuContext,
132 data: &[u8],
133 shape: &[usize],
134 dtype: DType,
135 ) -> Self {
136 let size_in_bytes = data.len() as u64;
137 let buffer = context
138 .device
139 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
140 label: Some("Byte Tensor"),
141 contents: data,
142 usage: wgpu::BufferUsages::STORAGE
143 | wgpu::BufferUsages::COPY_DST
144 | wgpu::BufferUsages::COPY_SRC,
145 });
146 Self {
147 data: Arc::new(TensorData {
148 buffer: Arc::new(buffer),
149 size_in_bytes,
150 pool: None,
151 }),
152 shape: shape.to_vec(),
153 dtype,
154 }
155 }
156
157 pub fn empty_fp16(context: &WgpuContext, shape: &[usize]) -> Self {
159 Self::empty_with_dtype(context, shape, DType::FP16)
160 }
161
162 pub fn reshaped(&self, new_shape: &[usize]) -> Self {
164 let current_elements: usize = self.shape.iter().product();
166 let new_elements: usize = new_shape.iter().product();
167 assert_eq!(
168 current_elements, new_elements,
169 "Cannot reshape tensor of size {} to {:?}",
170 current_elements, new_shape
171 );
172
173 Self {
174 data: self.data.clone(),
175 shape: new_shape.to_vec(),
176 dtype: self.dtype,
177 }
178 }
179
180 pub async fn to_vec(&self, context: &WgpuContext) -> Vec<f32> {
182 let size = self.size_in_bytes();
183 let staging = context.device.create_buffer(&wgpu::BufferDescriptor {
184 label: Some("Staging"),
185 size,
186 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
187 mapped_at_creation: false,
188 });
189 let mut encoder = context
190 .device
191 .create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
192 encoder.copy_buffer_to_buffer(&self.data.buffer, 0, &staging, 0, size);
193 context.queue.submit(Some(encoder.finish()));
194
195 let slice = staging.slice(..);
196 let (tx, rx) = futures_intrusive::channel::shared::oneshot_channel();
197 slice.map_async(wgpu::MapMode::Read, move |_| tx.send(()).unwrap());
198 context.device.poll(wgpu::Maintain::Wait);
199 rx.receive().await;
200
201 let data = slice.get_mapped_range();
202 let res = bytemuck::cast_slice(&data).to_vec();
203 drop(data);
204 staging.unmap();
205 res
206 }
207}