Skip to content

Commit 56d1544

Browse files
author
Paul Mattern
committed
feat: WgpuBackend creates second buffer from user data
1 parent d7ff92c commit 56d1544

File tree

4 files changed

+112
-82
lines changed

4 files changed

+112
-82
lines changed

shaders/dither.wgsl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
struct FragmentInput {
32
time: f32,
43
padding: f32,

src/backend/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ pub mod cpu;
22
pub mod wgpu;
33

44
#[repr(C)]
5-
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
6-
pub struct NoUserData;
5+
#[derive(Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
6+
pub struct NoUserData(f32);
77

88
pub trait TuiShaderBackend<T> {
99
fn execute(&mut self, width: u16, height: u16, user_data: &T) -> Vec<[u8; 4]>;

src/backend/wgpu.rs

Lines changed: 104 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,49 @@ use wgpu::util::DeviceExt;
66
use super::{NoUserData, TuiShaderBackend};
77

88
#[repr(C)]
9-
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
9+
#[derive(Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
1010
struct ShaderInput {
1111
// struct field order matters
1212
time: f32,
1313
padding: f32,
1414
resolution: [f32; 2],
1515
}
1616

17-
#[derive(Debug, Clone, Eq, PartialEq)]
17+
#[derive(Debug, Clone)]
1818
pub struct WgpuBackend<T>
1919
where
20-
T: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
20+
T: Copy + Clone + Default + bytemuck::Pod + bytemuck::Zeroable,
2121
{
2222
device: wgpu::Device,
2323
queue: wgpu::Queue,
2424
pipeline: wgpu::RenderPipeline,
25-
creation_time: Instant,
2625
texture: wgpu::Texture,
2726
output_buffer: wgpu::Buffer,
2827
shader_input_buffer: wgpu::Buffer,
2928
bind_group: wgpu::BindGroup,
29+
creation_time: Instant,
3030
width: u16,
3131
height: u16,
3232
_user_data: PhantomData<T>,
3333
}
3434

3535
impl<T> WgpuBackend<T>
3636
where
37-
T: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
37+
T: Copy + Clone + Default + bytemuck::Pod + bytemuck::Zeroable,
3838
{
3939
pub fn new(path_to_fragment_shader: &str, entry_point: &str) -> Self {
4040
Self::new_inner(path_to_fragment_shader, entry_point).block_on()
4141
}
4242

43-
async fn new_inner(path_to_fragment_shader: &str, entry_point: &str) -> Self {
43+
async fn get_device_and_queue() -> (wgpu::Device, wgpu::Queue) {
4444
let instance = wgpu::Instance::default();
4545

4646
let adapter = instance
4747
.request_adapter(&wgpu::RequestAdapterOptions::default())
4848
.await
4949
.expect("unable to create adapter from wgpu instance");
5050

51-
let (device, queue) = adapter
51+
let device_and_queue = adapter
5252
.request_device(
5353
&wgpu::DeviceDescriptor {
5454
label: None,
@@ -60,6 +60,41 @@ where
6060
)
6161
.await
6262
.expect("unable to create device and queue from wgpu adapter");
63+
device_and_queue
64+
}
65+
66+
fn create_texture(device: &wgpu::Device, width: u32, height: u32) -> wgpu::Texture {
67+
let texture_desc = wgpu::TextureDescriptor {
68+
size: wgpu::Extent3d {
69+
width,
70+
height,
71+
depth_or_array_layers: 1,
72+
},
73+
mip_level_count: 1,
74+
sample_count: 1,
75+
dimension: wgpu::TextureDimension::D2,
76+
format: wgpu::TextureFormat::Rgba8Unorm,
77+
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
78+
label: None,
79+
view_formats: &[wgpu::TextureFormat::Rgba8Unorm],
80+
};
81+
device.create_texture(&texture_desc)
82+
}
83+
84+
fn create_buffer(device: &wgpu::Device, width: u32, height: u32) -> wgpu::Buffer {
85+
let row_size = width * 4;
86+
let bytes_per_row = (row_size + 255) & !255;
87+
88+
device.create_buffer(&wgpu::BufferDescriptor {
89+
label: None,
90+
size: (bytes_per_row * height) as wgpu::BufferAddress,
91+
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
92+
mapped_at_creation: false,
93+
})
94+
}
95+
96+
async fn new_inner(path_to_fragment_shader: &str, entry_point: &str) -> Self {
97+
let (device, queue) = Self::get_device_and_queue().await;
6398

6499
let vertex_shader =
65100
device.create_shader_module(wgpu::include_wgsl!("../shaders/fullscreen_vertex.wgsl"));
@@ -73,12 +108,11 @@ where
73108
});
74109

75110
let creation_time = Instant::now();
76-
77111
let width = 64u16;
78112
let height = 64u16;
79113

80-
let texture = WgpuBackend::<T>::create_texture(&device, width.into(), height.into());
81-
let output_buffer = WgpuBackend::<T>::create_buffer(&device, width.into(), height.into());
114+
let texture = Self::create_texture(&device, width.into(), height.into());
115+
let output_buffer = Self::create_buffer(&device, width.into(), height.into());
82116

83117
let shader_input = ShaderInput {
84118
time: creation_time.elapsed().as_secs_f32(),
@@ -92,30 +126,58 @@ where
92126
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
93127
});
94128

129+
let user_data_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
130+
label: None,
131+
contents: bytemuck::cast_slice(&[T::default()]),
132+
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
133+
});
134+
95135
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
96-
entries: &[wgpu::BindGroupLayoutEntry {
97-
binding: 0,
98-
visibility: wgpu::ShaderStages::FRAGMENT,
99-
ty: wgpu::BindingType::Buffer {
100-
ty: wgpu::BufferBindingType::Uniform,
101-
has_dynamic_offset: false,
102-
min_binding_size: None,
136+
entries: &[
137+
wgpu::BindGroupLayoutEntry {
138+
binding: 0,
139+
visibility: wgpu::ShaderStages::FRAGMENT,
140+
ty: wgpu::BindingType::Buffer {
141+
ty: wgpu::BufferBindingType::Uniform,
142+
has_dynamic_offset: false,
143+
min_binding_size: None,
144+
},
145+
count: None,
103146
},
104-
count: None,
105-
}],
147+
wgpu::BindGroupLayoutEntry {
148+
binding: 1,
149+
visibility: wgpu::ShaderStages::FRAGMENT,
150+
ty: wgpu::BindingType::Buffer {
151+
ty: wgpu::BufferBindingType::Uniform,
152+
has_dynamic_offset: false,
153+
min_binding_size: None,
154+
},
155+
count: None,
156+
},
157+
],
106158
label: None,
107159
});
108160

109161
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
110162
layout: &bind_group_layout,
111-
entries: &[wgpu::BindGroupEntry {
112-
binding: 0,
113-
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
114-
buffer: &shader_input_buffer,
115-
offset: 0,
116-
size: None,
117-
}),
118-
}],
163+
entries: &[
164+
wgpu::BindGroupEntry {
165+
binding: 0,
166+
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
167+
buffer: &shader_input_buffer,
168+
offset: 0,
169+
size: None,
170+
}),
171+
},
172+
wgpu::BindGroupEntry {
173+
binding: 1,
174+
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
175+
buffer: &user_data_buffer,
176+
offset: 0,
177+
size: None,
178+
}),
179+
},
180+
],
119181
label: None,
120182
});
121183

@@ -166,53 +228,12 @@ where
166228
}
167229
}
168230

169-
fn create_texture(device: &wgpu::Device, width: u32, height: u32) -> wgpu::Texture {
170-
let texture_desc = wgpu::TextureDescriptor {
171-
size: wgpu::Extent3d {
172-
width,
173-
height,
174-
depth_or_array_layers: 1,
175-
},
176-
mip_level_count: 1,
177-
sample_count: 1,
178-
dimension: wgpu::TextureDimension::D2,
179-
format: wgpu::TextureFormat::Rgba8Unorm,
180-
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
181-
label: None,
182-
view_formats: &[wgpu::TextureFormat::Rgba8Unorm],
183-
};
184-
device.create_texture(&texture_desc)
185-
}
186-
187-
fn create_buffer(device: &wgpu::Device, width: u32, height: u32) -> wgpu::Buffer {
188-
let row_size = width * 4;
189-
let bytes_per_row = (row_size + 255) & !255;
190-
191-
device.create_buffer(&wgpu::BufferDescriptor {
192-
label: None,
193-
size: (bytes_per_row * height) as wgpu::BufferAddress,
194-
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
195-
mapped_at_creation: false,
196-
})
197-
}
198-
199-
fn bytes_per_row(&self, width: u16) -> u16 {
200-
let row_size = width * 4;
201-
(row_size + 255) & !255
202-
}
203-
204-
fn row_padding(&self, width: u16) -> u16 {
205-
let row_size = width * 4;
206-
let bytes_per_row = self.bytes_per_row(width);
207-
(bytes_per_row - row_size) / 4
208-
}
209-
210231
async fn execute_inner(&mut self, width: u16, height: u16, _user_data: &T) -> Vec<[u8; 4]> {
211-
if self.bytes_per_row(width) != self.bytes_per_row(self.width) || height != self.height {
232+
if bytes_per_row(width) != bytes_per_row(self.width) || height != self.height {
212233
self.texture = Self::create_texture(&self.device, width.into(), height.into());
213234
self.output_buffer = Self::create_buffer(&self.device, width.into(), height.into());
214235
}
215-
let bytes_per_row = self.bytes_per_row(width);
236+
let bytes_per_row = bytes_per_row(width);
216237

217238
let texture_view = self
218239
.texture
@@ -230,7 +251,6 @@ where
230251
let mut command_encoder = self
231252
.device
232253
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
233-
234254
{
235255
let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
236256
label: None,
@@ -299,7 +319,7 @@ where
299319
let mut buffer: Vec<[u8; 4]> = Vec::new();
300320
for y in 0..height {
301321
for x in 0..width {
302-
let index = (y * (width + self.row_padding(width)) + x) as usize;
322+
let index = (y * (width + row_padding(width)) + x) as usize;
303323
let pixel = padded_buffer[index];
304324
buffer.push(pixel);
305325
}
@@ -310,7 +330,7 @@ where
310330

311331
impl<T> TuiShaderBackend<T> for WgpuBackend<T>
312332
where
313-
T: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
333+
T: Copy + Clone + Default + bytemuck::Pod + bytemuck::Zeroable,
314334
{
315335
fn execute(&mut self, width: u16, height: u16, user_data: &T) -> Vec<[u8; 4]> {
316336
self.execute_inner(width, height, user_data).block_on()
@@ -322,3 +342,14 @@ impl Default for WgpuBackend<NoUserData> {
322342
Self::new("src/shaders/default_fragment.wgsl", "magenta")
323343
}
324344
}
345+
346+
fn bytes_per_row(width: u16) -> u16 {
347+
let row_size = width * 4;
348+
(row_size + 255) & !255
349+
}
350+
351+
fn row_padding(width: u16) -> u16 {
352+
let row_size = width * 4;
353+
let bytes_per_row = bytes_per_row(width);
354+
(bytes_per_row - row_size) / 4
355+
}

src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,14 @@ impl ShaderCanvasState<NoUserData> {
154154
let backend = Box::new(WgpuBackend::new(path_to_fragment_shader, entry_point));
155155
Self {
156156
backend,
157-
user_data: NoUserData,
157+
user_data: NoUserData::default(),
158158
}
159159
}
160160
}
161161

162162
impl<T> ShaderCanvasState<T>
163163
where
164-
T: Copy + bytemuck::Pod + bytemuck::Zeroable,
164+
T: Copy + Default + bytemuck::Pod + bytemuck::Zeroable,
165165
{
166166
pub fn wgpu_with_user_data(
167167
path_to_fragment_shader: &str,
@@ -181,7 +181,7 @@ impl ShaderCanvasState<NoUserData> {
181181
let backend = Box::new(CpuBackend::new(callback));
182182
Self {
183183
backend,
184-
user_data: NoUserData,
184+
user_data: NoUserData::default(),
185185
}
186186
}
187187
}
@@ -204,7 +204,7 @@ impl Default for ShaderCanvasState<NoUserData> {
204204
fn default() -> Self {
205205
Self {
206206
backend: Box::new(WgpuBackend::default()),
207-
user_data: NoUserData,
207+
user_data: NoUserData::default(),
208208
}
209209
}
210210
}
@@ -296,14 +296,14 @@ mod tests {
296296
#[test]
297297
fn default_wgsl_context() {
298298
let mut context = WgpuBackend::default();
299-
let raw_buffer = context.execute(64, 64, &NoUserData);
299+
let raw_buffer = context.execute(64, 64, &NoUserData::default());
300300
assert!(raw_buffer.iter().all(|pixel| pixel == &[255, 0, 255, 255]));
301301
}
302302

303303
#[test]
304304
fn different_entry_points() {
305305
let mut context = WgpuBackend::new("src/shaders/default_fragment.wgsl", "green");
306-
let raw_buffer = context.execute(64, 64, &NoUserData);
306+
let raw_buffer = context.execute(64, 64, &NoUserData::default());
307307
assert!(raw_buffer.iter().all(|pixel| pixel == &[0, 255, 0, 255]));
308308
}
309309

0 commit comments

Comments
 (0)