sketchbook_wgpu/wgpu/
display.rs

1pub mod shape;
2pub mod uniform;
3pub mod vertex;
4
5use std::collections::HashMap;
6use std::sync::Arc;
7use std::sync::Mutex;
8use sketchbook::aspects::*;
9use sketchbook::Point2;
10use wgpu::util::DeviceExt;
11use winit::event::VirtualKeyCode;
12
13use wgpu::RenderPipeline;
14use wgpu::Surface;
15use wgpu::SurfaceConfiguration;
16use wgpu::{Device, Queue};
17use winit::dpi::{PhysicalPosition, PhysicalSize};
18use winit::event::ElementState;
19use winit::event::MouseButton;
20use winit::event::WindowEvent;
21use winit::window::Window;
22
23use crate::fifo::FiFoPush;
24
25use super::vec_buffer::VecBuffer;
26use super::{DisplayInfo, Events};
27use std::time::Instant;
28
29use shape::*;
30use uniform::*;
31use vertex::*;
32
33use crate::double_buffer::*;
34use super::device::*;
35
36#[derive(Default)]
37pub struct Frame {
38    pub background: wgpu::Color,
39    pub buffer: Vec<ShapeRaw>,
40}
41
42pub struct Display {
43    event_queue: FiFoPush<Events>,
44    frame: DoubleBufferRead<Frame>,
45    info: Arc<Mutex<DisplayInfo>>,
46
47    shape_buffer: VecBuffer<ShapeRaw>,
48    background: wgpu::Color,
49
50    device: WgpuDevice,
51    render_pipeline: RenderPipeline,
52
53    vertex_buffer: wgpu::Buffer,
54    screen_buffer: wgpu::Buffer,
55    screen_bind_group: wgpu::BindGroup,
56    index_buffer: wgpu::Buffer,
57}
58
59const VERTICES: &[VertexRaw] = &[
60    Vertex { x: 1., y: 1. }.to_raw(),
61    Vertex { x: -1., y: 1. }.to_raw(),
62    Vertex { x: 1., y: -1. }.to_raw(),
63    Vertex { x: -1., y: -1. }.to_raw(),
64];
65
66const INDICES: &[u16] = &[0, 1, 2, 1, 2, 3];
67
68impl Display {
69    pub fn new(
70        instance: &wgpu::Instance,
71        window: Window,
72        event_queue: FiFoPush<Events>,
73        frame: DoubleBufferRead<Frame>,
74        info: Arc<Mutex<DisplayInfo>>,
75    ) -> Display {
76        let surface = WgpuSurface::for_window(instance, window);
77        let adapter = surface.best_adapter(instance, WgpuSurface::prefer_high_power).expect("Failed to get adapter.");
78        println!("Adapter: {:?}", adapter.adapter.get_info());
79        let mut device = pollster::block_on(adapter.create_device()).expect("Failed to get device.");
80
81        let vertex_buffer = device.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
82            label: Some("Vertex Buffer"),
83            contents: bytemuck::cast_slice(VERTICES),
84            usage: wgpu::BufferUsages::VERTEX,
85        });
86
87        let index_buffer = device.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
88            label: Some("Index Buffer"),
89            contents: bytemuck::cast_slice(INDICES),
90            usage: wgpu::BufferUsages::INDEX,
91        });
92
93        let shape_buffer = VecBuffer::new(
94            &device.device,
95            wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
96        );
97
98        let screen_uniform = Uniform {
99            surface_size: device.inner_size(),
100            scale: device.scale_factor(),
101        }
102        .to_raw();
103        let screen_buffer = device.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
104            label: Some("Screen Buffer"),
105            contents: bytemuck::cast_slice(&[screen_uniform]),
106            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
107        });
108
109        let screen_bind_group_layout =
110            device.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
111                entries: &[wgpu::BindGroupLayoutEntry {
112                    binding: 0,
113                    visibility: wgpu::ShaderStages::VERTEX,
114                    ty: wgpu::BindingType::Buffer {
115                        ty: wgpu::BufferBindingType::Uniform,
116                        has_dynamic_offset: false,
117                        min_binding_size: None,
118                    },
119                    count: None,
120                }],
121                label: Some("screen_bind_group_layout"),
122            });
123
124        let screen_bind_group = device.device.create_bind_group(&wgpu::BindGroupDescriptor {
125            layout: &screen_bind_group_layout,
126            entries: &[wgpu::BindGroupEntry {
127                binding: 0,
128                resource: screen_buffer.as_entire_binding(),
129            }],
130            label: Some("screen_bind_group"),
131        });
132
133        let render_pipeline = device.create_pipeline(
134            include_str!("shader.wgsl"),
135            &[&screen_bind_group_layout],
136            &[VertexRaw::description(), ShapeRaw::description()],
137        );
138
139        Self {
140            vertex_buffer,
141            screen_buffer,
142            screen_bind_group,
143            index_buffer,
144            frame,
145            event_queue,
146            info,
147            device,
148            render_pipeline,
149            shape_buffer,
150            background: wgpu::Color { r: 0.1, g: 0.2, b: 0.3, a: 1.0 },
151        }
152    }
153
154    pub fn trigger_draw(&mut self) {
155        self.event_queue.push(Events::Draw(draw::env_api::Events::Draw));
156    }
157
158    pub fn mouse_move(&mut self, position: PhysicalPosition<f64>) {
159        let position = position.to_logical(self.device.scale_factor());
160        self.event_queue.push(Events::Mouse(mouse::env_api::Events::MoveAbsolute(Point2 {
161            x: position.x,
162            y: position.y,
163        })));
164    }
165
166    pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) {
167        let event = match (state, button) {
168            (ElementState::Pressed, button) => {
169                mouse::env_api::Events::Press(button)
170            }
171            (ElementState::Released, button) => {
172                mouse::env_api::Events::Release(button)
173            }
174        };
175        self.event_queue.push(Events::Mouse(event));
176    }
177
178    pub fn keyboard_input(&mut self, keycode: VirtualKeyCode, state: ElementState) {
179        match state {
180            ElementState::Pressed => {
181                self.event_queue
182                    .push(Events::Keyboard(keyboard::env_api::Events::Press(keycode)));
183            }
184            ElementState::Released => {
185                self.event_queue
186                    .push(Events::Keyboard(keyboard::env_api::Events::Release(keycode)));
187            }
188        }
189    }
190
191    pub fn close(&mut self) {
192        self.event_queue.push(Events::Close);
193    }
194
195    pub fn window_request_redraw(&mut self) {
196        self.device.request_redraw();
197    }
198
199    pub fn handle_window_event(
200        &mut self,
201        event: &WindowEvent<'_>,
202    ) {
203        match event {
204            WindowEvent::Resized(size) => {
205                self.resize(*size);
206            }
207            WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
208                self.resize(**new_inner_size);
209            }
210            WindowEvent::CursorMoved { position, .. } => {
211                self.mouse_move(*position);
212            }
213            WindowEvent::MouseInput { state, button, .. } => {
214                self.mouse_input(*state, *button);
215            }
216            WindowEvent::KeyboardInput { input, .. } => {
217                if let Some(keycode) = input.virtual_keycode {
218                    self.keyboard_input(keycode, input.state);
219                }
220            }
221            WindowEvent::CloseRequested => {
222                self.close();
223            }
224            _ => {}
225        }
226    }
227
228    pub fn resize(&mut self, size: PhysicalSize<u32>) {
229        self.device.resize(size);
230
231        {
232            let mut info = self.info.lock().unwrap();
233            let size = size.to_logical(self.device.scale_factor());
234            info.width = size.width;
235            info.height = size.height;
236        }
237
238        self.trigger_draw();
239
240        self.device.queue.write_buffer(
241            &self.screen_buffer,
242            0,
243            bytemuck::cast_slice(&[Uniform {
244                surface_size: size,
245                scale: self.device.scale_factor(),
246            }
247            .to_raw()]),
248        );
249    }
250
251    fn update_draw_buffer(&mut self) {
252        if let Some(frame) = self.frame.if_changed() {
253            self.background = frame.background;
254            self.shape_buffer.load_data(&self.device.device, &self.device.queue, &frame.buffer);
255        }
256    }
257
258    pub fn redraw(&mut self) {
259        self.update_draw_buffer();
260        
261        let result = self.device.redraw(|view, encoder| {
262            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
263                label: Some("Render Pass"),
264                color_attachments: &[wgpu::RenderPassColorAttachment {
265                    view,
266                    resolve_target: None,
267                    ops: wgpu::Operations {
268                        load: wgpu::LoadOp::Clear(self.background),
269                        store: true,
270                    },
271                }],
272                depth_stencil_attachment: None,
273            });
274
275            render_pass.set_pipeline(&self.render_pipeline);
276            render_pass.set_bind_group(0, &self.screen_bind_group, &[]);
277            render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
278            render_pass.set_vertex_buffer(1, self.shape_buffer.slice());
279            render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
280            render_pass.draw_indexed(
281                0..INDICES.len() as u32,
282                0,
283                0..self.shape_buffer.len() as u32,
284            );
285        });
286
287        match result {
288            Err(wgpu::SurfaceError::Outdated | wgpu::SurfaceError::Lost) => {
289                // fix surface getting out of sync with window
290                self.resize(self.device.inner_size());
291            }
292            _ => {}
293        }
294    }
295}