aspen_renderer/
lib.rs

1pub mod window_surface;
2pub mod drawable;
3pub mod renderpass;
4pub mod submit_system;
5pub mod render_system;
6
7use std::{
8    collections::HashMap, 
9    sync::{
10        mpsc::{
11            sync_channel,
12            channel, 
13            Receiver, 
14            Sender, 
15            SyncSender
16        }, 
17        Arc, 
18        Mutex
19    }, 
20    thread
21};
22
23use render_system::RenderSystem;
24use vulkano::{
25    command_buffer::allocator::StandardCommandBufferAllocator, 
26    descriptor_set::allocator::StandardDescriptorSetAllocator, 
27    device::{
28        physical::PhysicalDeviceType, 
29        Device, 
30        DeviceCreateInfo, 
31        DeviceExtensions, 
32        Features, 
33        Queue, 
34        QueueCreateInfo, 
35        QueueFlags
36    }, 
37    image::{
38        view::ImageView, 
39        Image, 
40        ImageUsage
41    }, 
42    instance::{
43        Instance, 
44        InstanceCreateFlags, 
45        InstanceCreateInfo
46    }, 
47    memory::allocator::StandardMemoryAllocator, 
48    pipeline::graphics::viewport::Viewport, 
49    render_pass::{
50        Framebuffer, 
51        FramebufferCreateInfo, 
52        RenderPass
53    }, 
54    swapchain::{
55        Surface, 
56        Swapchain, 
57        SwapchainCreateInfo
58    }, 
59    VulkanLibrary
60};
61
62use window_surface::WindowSurface;
63use winit::{
64    dpi::PhysicalSize, event_loop::EventLoop, window::{WindowBuilder, WindowId} 
65};
66
67#[derive(Clone)]
68pub struct GraphicsObjects {
69    pub device: Arc<Device>,
70    pub graphics_queue: Arc<Queue>,
71    pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
72    pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
73    pub memory_allocator: Arc<StandardMemoryAllocator>
74}
75
76pub struct Renderer {
77    pub comms: RenderThreadComms,
78    pub windows: HashMap<WindowId, Arc<Mutex<WindowSurface>>>,
79    pub graphics_objects: GraphicsObjects,
80}
81
82impl Renderer {
83    pub fn new<ELT>(event_loop: &EventLoop<ELT>) -> (Self, WindowId) {
84        let library = VulkanLibrary::new().unwrap();
85        let required_extensions = Surface::required_extensions(&event_loop);
86
87        let instance = Instance::new(
88            library,
89            InstanceCreateInfo {
90                flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
91                enabled_extensions: required_extensions,
92                ..Default::default()
93            },
94        ).unwrap();
95
96        let window = Arc::new(
97            WindowBuilder::new()
98                .with_title("Primary window")
99                .with_inner_size(PhysicalSize::new(400, 400))
100                .build(&event_loop)
101                .unwrap()
102        );
103        let surface = Surface::from_window(instance.clone(), window.clone()).unwrap();
104        
105        let device_extensions = DeviceExtensions {
106            khr_swapchain: true,
107            ..DeviceExtensions::empty()
108        };
109        
110        let (physical_device, queue_family_index) = instance
111            .enumerate_physical_devices()
112            .unwrap()
113            .filter(|p| {
114                p.supported_extensions().contains(&device_extensions)
115            })
116            .filter_map(|p| {
117                p.queue_family_properties()
118                    .iter()
119                    .enumerate()
120                    .position(|(i, q)| {
121                        q.queue_flags.intersects(QueueFlags::GRAPHICS)
122                        && p.surface_support(i as u32, &surface).unwrap_or(false)
123                    })
124                    .map(|i| (p, i as u32))
125                })
126                .min_by_key(|(p, _)| {
127                    match p.properties().device_type {
128                        PhysicalDeviceType::DiscreteGpu => 0,
129                        PhysicalDeviceType::IntegratedGpu => 1,
130                        PhysicalDeviceType::VirtualGpu => 2,
131                        PhysicalDeviceType::Cpu => 3,
132                        PhysicalDeviceType::Other => 4,
133                        _ => 5,
134                    }
135                })
136            .expect("no suitable physical device found");
137        
138        
139        println!(
140            "Using device: {} (type: {:?})\nVulkan version: {}\nCompute subgroup size: {}\nVertex buffer binding limit: {}",
141            physical_device.properties().device_name,
142            physical_device.properties().device_type,
143            physical_device.api_version(),
144            physical_device.properties().subgroup_size.unwrap(),
145            physical_device.properties().max_vertex_input_bindings,
146        );
147
148        let (device, mut queues) = Device::new(
149            physical_device,
150            DeviceCreateInfo {
151                enabled_extensions: device_extensions,
152                enabled_features: Features {
153                    ..Default::default()
154                },
155                queue_create_infos: vec![QueueCreateInfo {
156                    queue_family_index,
157                    ..Default::default()
158                }],
159                
160                ..Default::default()
161            },
162        ).unwrap();
163
164        let queue = queues.next().unwrap();
165
166        let (swapchain, images) = {
167            let surface_capabilities = device
168                .physical_device()
169                .surface_capabilities(&surface, Default::default())
170                .unwrap();
171        
172            let image_format = device
173                .physical_device()
174                .surface_formats(&surface, Default::default())
175                .unwrap()[0]
176                .0;
177            
178            Swapchain::new(
179                device.clone(),
180                surface,
181                SwapchainCreateInfo {
182                    min_image_count: surface_capabilities.min_image_count.max(2),
183                    image_format,
184                    image_extent: window.inner_size().into(),
185                    image_usage: ImageUsage::COLOR_ATTACHMENT,
186                    composite_alpha: surface_capabilities
187                    .supported_composite_alpha
188                    .into_iter()
189                    .next()
190                    .unwrap(),
191                    present_mode: vulkano::swapchain::PresentMode::Fifo,
192                    ..Default::default()
193                },
194            ).unwrap()
195        };
196
197        let renderpass = vulkano::single_pass_renderpass!(
198            device.clone(),
199            attachments: {
200                color: {
201                    format: swapchain.image_format(),
202                    samples: 1,
203                    load_op: Clear,
204                    store_op: Store,
205                },
206            },
207            pass: {
208                color: [color],
209                depth_stencil: {},
210            },
211        )
212        .unwrap();
213
214        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
215
216        let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
217            device.clone(), 
218            Default::default()
219        ));
220
221        let mut viewport = Viewport {
222            offset: [0.0, 0.0],
223            extent: [0.0, 0.0],
224            depth_range: 0.0..=1.0,
225        };
226
227        let framebuffers = window_size_dependent_setup(&images, renderpass.clone(), &mut viewport);
228        let previous_frame_fences = (0..images.len())
229            .map(|_| { None })
230            .collect::<Vec<_>>();
231    
232        let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
233            device.clone(),
234            Default::default(),
235        )); 
236
237        let mut windows = HashMap::new();
238        let window_id = window.id();
239        windows.insert(
240            window_id,
241            Arc::new(
242                Mutex::new(
243                    WindowSurface {
244                        window,
245                        swapchain,
246                        images,
247                        framebuffers,
248                        renderpass: renderpass.clone(),
249                        viewport,
250                        recreate_swapchain: true,
251                        previous_frame_fences,
252                        previous_frame_index: 0
253                    }
254                )
255            )
256        );
257
258        //let window_2 = WindowSurface::new(event_loop, device.clone());
259        //windows.insert(window_2.window.id(), Arc::new(Mutex::new(window_2)));
260
261        let graphics_objects_original = GraphicsObjects {
262            device: device.clone(),
263            graphics_queue: queue.clone(),
264            descriptor_set_allocator: descriptor_set_allocator.clone(),
265            command_buffer_allocator: command_buffer_allocator.clone(),
266            memory_allocator: memory_allocator.clone(),
267        };
268
269        let graphics_objects = graphics_objects_original.clone();
270
271        let (sender, reciever) = sync_channel::<(Box<dyn RenderSystem + Send>, Sender<()>)>(1);
272        let render_closure = move || {
273            let graphics_objects = Arc::new(graphics_objects_original.clone());
274            loop {
275                match reciever.recv() {
276                    Err(_) => break,
277                    Ok((mut rendergraph, msender)) => {
278                        rendergraph.run(graphics_objects.clone());
279
280                        _ = msender.send(())
281                    },
282                }
283            }
284        };
285
286        let render_thread = thread::Builder::new()
287            .name("main_render_thread".to_string())
288            .spawn(render_closure)
289            .expect("failed to spawn main render thread");
290
291        let comms = RenderThreadComms {
292            sender: Some(sender),
293            render_thread: Some(render_thread)
294        };
295        
296        (
297            Self {
298                comms,
299                windows,
300                graphics_objects
301            }, 
302            window_id
303        )
304    }
305
306    pub fn device(&self) -> &Arc<Device> {
307        &self.graphics_objects.device
308    }
309
310    pub fn allocator(&self) -> &Arc<StandardMemoryAllocator> {
311        &self.graphics_objects.memory_allocator
312    }
313}
314
315pub struct RenderThreadComms {
316    pub sender: Option<SyncSender<(Box<dyn RenderSystem + Send>, Sender<()>)>>,
317    pub render_thread: Option<thread::JoinHandle<()>>,
318}
319
320impl RenderThreadComms {
321    pub fn send(&mut self, render_system: Box<dyn RenderSystem + Send>) -> PresentBarrier {
322        let (sender, reciever) = channel();
323        self.sender.as_ref().unwrap().send((render_system, sender)).expect("Render thread hung up");
324        PresentBarrier {
325            reciever: Some(reciever)
326        }
327    }
328}
329
330impl Drop for RenderThreadComms {
331    fn drop(&mut self) {
332        _ = self.sender.take();
333        _ = self.render_thread.take().unwrap().join();
334    }
335}
336
337pub struct PresentBarrier {
338    reciever: Option<Receiver<()>>
339}
340
341impl PresentBarrier {
342    pub fn blocking_wait(&mut self) {
343        if let Some(reciever) = self.reciever.as_ref() {
344            _ = reciever.recv();
345            self.reciever = None
346        }
347    }
348}
349
350impl Drop for PresentBarrier {
351    fn drop(&mut self) {
352        self.blocking_wait()
353    }
354}
355
356fn window_size_dependent_setup(
357    images: &[Arc<Image>],
358    render_pass: Arc<RenderPass>,
359    viewport: &mut Viewport,
360) -> Vec<Arc<Framebuffer>> {
361    let extent = images[0].extent();
362    viewport.extent = [extent[0] as f32, extent[1] as f32];
363
364    images
365        .iter()
366        .map(|image| {
367            let view = ImageView::new_default(image.clone()).unwrap();
368            Framebuffer::new(
369                render_pass.clone(),
370                FramebufferCreateInfo {
371                    attachments: vec![view],
372                    ..Default::default()
373                },
374            )
375            .unwrap()
376        })
377        .collect::<Vec<_>>()
378}