aboutsummaryrefslogtreecommitdiff
path: root/vgcodec/src/diff.rs
blob: 44efabe34cce81f711aa77ea7f16bd90380bbd88 (plain)
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(&mut 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
    }
}