aboutsummaryrefslogtreecommitdiff
path: root/vgcodec/src/paint.rs
blob: 33ab572b8049a43630d40ff5e178196e54dd8a90 (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
use bytemuck::{Pod, Zeroable};
use std::{borrow::Cow, sync::Arc};
use wgpu::{util::DeviceExt, BindGroup, Buffer, ComputePipeline, Extent3d, Texture};

use crate::app::App;

pub struct Painter {
    app: Arc<App>,
    size: Extent3d,

    pipeline: ComputePipeline,
    bind_group: BindGroup,

    uniform_buffer: Buffer,
}

#[repr(C)]
#[derive(Pod, Zeroable, Clone, Copy)]
pub struct PaintUniforms {
    pub x: f32,
    pub y: f32,
    pub rx: f32,
    pub ry: f32,
    pub r: f32,
    pub g: f32,
    pub b: f32,
}

impl Painter {
    pub fn new(app: &Arc<App>, extent: Extent3d, texture: &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!("paint.wgsl"))),
        });

        // let uniform_buffer_size = std::mem::size_of::<PaintUniforms>() as wgpu::BufferAddress;
        let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(&[PaintUniforms::zeroed()]),
            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
        });

        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(
                        &texture.create_view(&wgpu::TextureViewDescriptor::default()),
                    ),
                },
                wgpu::BindGroupEntry {
                    binding: 1,
                    resource: uniform_buffer.as_entire_binding(),
                },
            ],
        });
        Self {
            app: app.clone(),
            size: extent,
            pipeline,
            uniform_buffer,
            bind_group,
        }
    }

    pub fn run(&self, params: PaintUniforms) {
        let App { device, queue, .. } = self.app.as_ref();

        queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[params]));

        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);
        }
        queue.submit(Some(encoder.finish()));
    }
}