1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
use std::{borrow::Cow, sync::Arc};
use wgpu::{util::DeviceExt, BindGroup, Buffer, ComputePipeline, Extent3d, Texture};
use crate::app::App;
pub struct Differ {
app: Arc<App>,
size: Extent3d,
pipeline: ComputePipeline,
bind_group: BindGroup,
counter_buffer_size: u64,
counter_buffer: Buffer,
counter_staging_buffer: Buffer,
}
impl Differ {
pub fn new(app: &Arc<App>, extent: Extent3d, tex_a: &Texture, tex_b: &Texture) -> Self {
let App { device, .. } = app.as_ref();
let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("diff.wgsl"))),
});
let counter_buffer_size = std::mem::size_of::<u32>() as wgpu::BufferAddress;
let counter_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: counter_buffer_size,
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let counter_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[0u32]),
usage: wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
});
let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: None,
layout: None,
module: &cs_module,
entry_point: "main",
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &pipeline.get_bind_group_layout(0),
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(
&tex_a.create_view(&wgpu::TextureViewDescriptor::default()),
),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(
&tex_b.create_view(&wgpu::TextureViewDescriptor::default()),
),
},
wgpu::BindGroupEntry {
binding: 2,
resource: counter_buffer.as_entire_binding(),
},
],
});
Self {
app: app.clone(),
size: extent,
pipeline,
counter_buffer_size,
counter_buffer,
bind_group,
counter_staging_buffer,
}
}
pub async fn run(&self) -> u32 {
let App { device, queue, .. } = self.app.as_ref();
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
let mut cpass =
encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });
cpass.set_pipeline(&self.pipeline);
cpass.set_bind_group(0, &self.bind_group, &[]);
cpass.dispatch_workgroups(self.size.width, self.size.height, 1);
}
encoder.copy_buffer_to_buffer(
&self.counter_buffer,
0,
&self.counter_staging_buffer,
0,
self.counter_buffer_size,
);
queue.submit(Some(encoder.finish()));
let buffer_slice = self.counter_staging_buffer.slice(..);
let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
buffer_slice.map_async(wgpu::MapMode::Read, move |v| {
sender.send(v.unwrap()).unwrap()
});
device.poll(wgpu::Maintain::Wait);
receiver.receive().await;
let data = buffer_slice.get_mapped_range();
let result: u32 = bytemuck::cast_slice(&data).to_vec()[0];
drop(data);
self.counter_staging_buffer.unmap();
result
}
}
|