- The state of the game is now tracked using a simple state
  machine, where the main struct representing the game is `Game`
  and its state a generic implementing `GameState` on that struct,
  the following states exist:
  - `Unstarted`: Nothing has been done yet
  - `RenderAvailable`: The very basic things for rendering are available
    (sdl context, entry, instance, device, cmdbuf, surface, etc)
  - `LoadingWorld`: We are loading into a world, the only thing that
    can be done here currently is add things to be rendered (Components)
	of which only the `Cube` is available, with the skybox being
	automaticall added.
  - `InWorld`: We have loaded a world and can (theoretically) render things
    and move about
- The render logic now lives in `render/` and is split both by phase, as well as
  components and the swapchain having their own modules
- The input logic now lives in input and constits of one trait that should be
  implemented for states that should handle input, and is currently capable of
  handling mouse movenent, key presses and keys that should be held down (ex,
  movement keys)
- The game logic lives in `game/` and is/will be responsible for driving both
  the input and render modules
Note: the current commit is broken, as our surface is lost when returning from
`Game<Unstarted>::init_render`
			
			
				pull/3/head
			
			
		
							parent
							
								
									8168eebf7b
								
							
						
					
					
						commit
						2f15842ca4
					
				@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    process, thread,
 | 
				
			||||||
 | 
					    time::{Duration, Instant},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use sdl2::{
 | 
				
			||||||
 | 
					    event::{Event, WindowEvent},
 | 
				
			||||||
 | 
					    keyboard::Keycode,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{Game, InWorld, RenderAvailable, input::InputHandler};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Default)]
 | 
				
			||||||
 | 
					pub struct Vector3 {
 | 
				
			||||||
 | 
					    pub x: f32,
 | 
				
			||||||
 | 
					    pub y: f32,
 | 
				
			||||||
 | 
					    pub z: f32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Default)]
 | 
				
			||||||
 | 
					pub struct Camera {
 | 
				
			||||||
 | 
					    pub origin: Vector3,
 | 
				
			||||||
 | 
					    pub rotation: Vector3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Game<InWorld> {
 | 
				
			||||||
 | 
					    pub fn main_loop(mut self) -> Game<RenderAvailable> {
 | 
				
			||||||
 | 
					        let mut event_pump = self
 | 
				
			||||||
 | 
					            .state
 | 
				
			||||||
 | 
					            .sdl_context
 | 
				
			||||||
 | 
					            .event_pump()
 | 
				
			||||||
 | 
					            .expect("Failed to get event pump");
 | 
				
			||||||
 | 
					        let mouse = self.state.sdl_context.mouse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mouse.set_relative_mouse_mode(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut running = true;
 | 
				
			||||||
 | 
					        while running {
 | 
				
			||||||
 | 
					            let now = Instant::now();
 | 
				
			||||||
 | 
					            for event in event_pump.poll_iter() {
 | 
				
			||||||
 | 
					                match event {
 | 
				
			||||||
 | 
					                    // Setting running to false just returns to
 | 
				
			||||||
 | 
					                    // RenderAvailable state (and then main menu)
 | 
				
			||||||
 | 
					                    Event::Quit { .. } => process::exit(0),
 | 
				
			||||||
 | 
					                    Event::Window {
 | 
				
			||||||
 | 
					                        win_event: WindowEvent::Resized(w, h),
 | 
				
			||||||
 | 
					                        ..
 | 
				
			||||||
 | 
					                    } => {
 | 
				
			||||||
 | 
					                        self.window_resize((w as u32, h as u32));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    Event::KeyDown {
 | 
				
			||||||
 | 
					                        keycode: Some(keycode),
 | 
				
			||||||
 | 
					                        keymod,
 | 
				
			||||||
 | 
					                        repeat,
 | 
				
			||||||
 | 
					                        ..
 | 
				
			||||||
 | 
					                    } => self.handle_keydown(keycode, keymod, repeat),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Event::KeyUp {
 | 
				
			||||||
 | 
					                        keycode: Some(keycode),
 | 
				
			||||||
 | 
					                        keymod,
 | 
				
			||||||
 | 
					                        repeat,
 | 
				
			||||||
 | 
					                        ..
 | 
				
			||||||
 | 
					                    } => self.handle_keyup(keycode, keymod, repeat),
 | 
				
			||||||
 | 
					                    Event::MouseMotion {
 | 
				
			||||||
 | 
					                        mousestate,
 | 
				
			||||||
 | 
					                        x,
 | 
				
			||||||
 | 
					                        y,
 | 
				
			||||||
 | 
					                        xrel,
 | 
				
			||||||
 | 
					                        yrel,
 | 
				
			||||||
 | 
					                        ..
 | 
				
			||||||
 | 
					                    } => self.handle_mouse_motion(mousestate, (x, y), (xrel, yrel)),
 | 
				
			||||||
 | 
					                    _ => {}
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            event_pump
 | 
				
			||||||
 | 
					                .keyboard_state()
 | 
				
			||||||
 | 
					                .pressed_scancodes()
 | 
				
			||||||
 | 
					                .filter_map(Keycode::from_scancode)
 | 
				
			||||||
 | 
					                .for_each(|k| self.handle_cont_key(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.render_frame();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let elapsed = now.elapsed();
 | 
				
			||||||
 | 
					            let delay = (1_000_000u128 / 60).saturating_sub(elapsed.as_micros());
 | 
				
			||||||
 | 
					            thread::sleep(Duration::from_micros(delay as u64));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Game {
 | 
				
			||||||
 | 
					            state: RenderAvailable {
 | 
				
			||||||
 | 
					                sdl_context: self.state.sdl_context,
 | 
				
			||||||
 | 
					                window: self.state.window,
 | 
				
			||||||
 | 
					                ctx: self.state.ctx,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					use sdl2::{
 | 
				
			||||||
 | 
					    keyboard::{Keycode, Mod},
 | 
				
			||||||
 | 
					    mouse::MouseState,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{Game, InWorld};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::InputHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MOV_STEP: f32 = 0.05;
 | 
				
			||||||
 | 
					const ROT_MOUSE_SCALE: f32 = 0.001;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl InputHandler for Game<InWorld> {
 | 
				
			||||||
 | 
					    fn handle_cont_key(&mut self, keycode: Keycode) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state: InWorld { camera, .. },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match keycode {
 | 
				
			||||||
 | 
					            Keycode::W => {
 | 
				
			||||||
 | 
					                camera.origin.x -= -camera.rotation.y.sin() * MOV_STEP;
 | 
				
			||||||
 | 
					                camera.origin.z -= camera.rotation.y.cos() * MOV_STEP;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Keycode::S => {
 | 
				
			||||||
 | 
					                camera.origin.x += -camera.rotation.y.sin() * MOV_STEP;
 | 
				
			||||||
 | 
					                camera.origin.z += camera.rotation.y.cos() * MOV_STEP;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Keycode::A => {
 | 
				
			||||||
 | 
					                camera.origin.x += camera.rotation.y.cos() * MOV_STEP;
 | 
				
			||||||
 | 
					                camera.origin.z += camera.rotation.y.sin() * MOV_STEP;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Keycode::D => {
 | 
				
			||||||
 | 
					                camera.origin.z -= camera.rotation.y.sin() * MOV_STEP;
 | 
				
			||||||
 | 
					                camera.origin.x -= camera.rotation.y.cos() * MOV_STEP;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Keycode::Space => {
 | 
				
			||||||
 | 
					                camera.origin.y += MOV_STEP;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Keycode::LShift => {
 | 
				
			||||||
 | 
					                camera.origin.y -= MOV_STEP;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => {}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn handle_keydown(&mut self, keycode: Keycode, modifier: Mod, repeat: bool) {
 | 
				
			||||||
 | 
					        match keycode {
 | 
				
			||||||
 | 
					            Keycode::Escape => {
 | 
				
			||||||
 | 
					                let mouse = self.state.sdl_context.mouse();
 | 
				
			||||||
 | 
					                mouse.set_relative_mouse_mode(!mouse.relative_mouse_mode());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => {}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn handle_mouse_motion(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        state: MouseState,
 | 
				
			||||||
 | 
					        abs: (i32, i32),
 | 
				
			||||||
 | 
					        (xrel, yrel): (i32, i32),
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        if self.state.sdl_context.mouse().relative_mouse_mode() {
 | 
				
			||||||
 | 
					            self.state.camera.rotation.y -= xrel as f32 * ROT_MOUSE_SCALE;
 | 
				
			||||||
 | 
					            self.state.camera.rotation.x -= yrel as f32 * ROT_MOUSE_SCALE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					mod ingame_input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use sdl2::{
 | 
				
			||||||
 | 
					    keyboard::{Keycode, Mod},
 | 
				
			||||||
 | 
					    mouse::MouseState,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// More methods to be added for other forms of input
 | 
				
			||||||
 | 
					pub trait InputHandler {
 | 
				
			||||||
 | 
					    // Handle keys which are meant to be held down and repeated every frame, ex movement keys
 | 
				
			||||||
 | 
					    fn handle_cont_key(&mut self, keycode: Keycode) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Handle single keypresses or keys held down after the repear delay
 | 
				
			||||||
 | 
					    fn handle_keydown(&mut self, keycode: Keycode, modifier: Mod, repeat: bool) {}
 | 
				
			||||||
 | 
					    fn handle_keyup(&mut self, keycode: Keycode, modifier: Mod, repeat: bool) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Handle mouse movements
 | 
				
			||||||
 | 
					    fn handle_mouse_motion(&mut self, state: MouseState, abs: (i32, i32), rel: (i32, i32)) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								@ -0,0 +1,413 @@
 | 
				
			|||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ash::vk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{Game, LoadingWorld, RenderCtx, render::MemType};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::loading_world::WorldComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Cube {
 | 
				
			||||||
 | 
					    mesh_buf: vk::Buffer,
 | 
				
			||||||
 | 
					    pipeline: vk::Pipeline,
 | 
				
			||||||
 | 
					    pipe_layout: vk::PipelineLayout,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MESH_SIZE: u64 = 36 * 2 * 4 * 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[rustfmt::skip]
 | 
				
			||||||
 | 
					const POSITIONS: [f32; 36 * 2 * 4] = [
 | 
				
			||||||
 | 
					    // BOTTOM
 | 
				
			||||||
 | 
					    -0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TOP
 | 
				
			||||||
 | 
					    0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, -1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, -1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, -1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, -1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, -1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, -1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // FRONT
 | 
				
			||||||
 | 
					    -0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, -1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, -1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, -1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, -1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, -1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, -1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // BACK
 | 
				
			||||||
 | 
					    0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, 1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, 1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, 1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, 1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, 1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    0.0, 0.0, 1.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // LEFT
 | 
				
			||||||
 | 
					    -0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    -1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    -1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    -1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    -1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    -1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    -1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // RIGHT
 | 
				
			||||||
 | 
					    0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 2.0, 1.0,
 | 
				
			||||||
 | 
					    1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, 0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    0.5, -0.5, 1.0, 1.0,
 | 
				
			||||||
 | 
					    1.0, 0.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WorldComponent for Cube {
 | 
				
			||||||
 | 
					    fn descriptors(&self) -> std::collections::HashMap<vk::DescriptorType, u32> {
 | 
				
			||||||
 | 
					        let mut map = HashMap::new();
 | 
				
			||||||
 | 
					        map.insert(vk::DescriptorType::COMBINED_IMAGE_SAMPLER, 1);
 | 
				
			||||||
 | 
					        map.insert(vk::DescriptorType::STORAGE_BUFFER, 1);
 | 
				
			||||||
 | 
					        map
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn desc_layout(&self, ctx: &RenderCtx) -> vk::DescriptorSetLayout {
 | 
				
			||||||
 | 
					        let storage_binding = vk::DescriptorSetLayoutBinding::default()
 | 
				
			||||||
 | 
					            .binding(0)
 | 
				
			||||||
 | 
					            .descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
 | 
				
			||||||
 | 
					            .descriptor_count(1)
 | 
				
			||||||
 | 
					            .stage_flags(vk::ShaderStageFlags::VERTEX);
 | 
				
			||||||
 | 
					        let image_binding = vk::DescriptorSetLayoutBinding::default()
 | 
				
			||||||
 | 
					            .binding(1)
 | 
				
			||||||
 | 
					            .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
 | 
				
			||||||
 | 
					            .descriptor_count(1)
 | 
				
			||||||
 | 
					            .stage_flags(vk::ShaderStageFlags::FRAGMENT);
 | 
				
			||||||
 | 
					        let layouts = [storage_binding, image_binding];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&layouts);
 | 
				
			||||||
 | 
					        let layout = unsafe {
 | 
				
			||||||
 | 
					            ctx.dev
 | 
				
			||||||
 | 
					                .create_descriptor_set_layout(&layout_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create descriptor set layout")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        layout
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_desc_set(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        ctx: &RenderCtx,
 | 
				
			||||||
 | 
					        desc_set: vk::DescriptorSet,
 | 
				
			||||||
 | 
					        skybox: (vk::ImageView, vk::Sampler),
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let buf_info = vk::DescriptorBufferInfo::default()
 | 
				
			||||||
 | 
					            .buffer(self.mesh_buf)
 | 
				
			||||||
 | 
					            .offset(0)
 | 
				
			||||||
 | 
					            .range(vk::WHOLE_SIZE);
 | 
				
			||||||
 | 
					        let buf_infos = [buf_info];
 | 
				
			||||||
 | 
					        let buf_desc = vk::WriteDescriptorSet::default()
 | 
				
			||||||
 | 
					            .dst_set(desc_set)
 | 
				
			||||||
 | 
					            .dst_binding(0)
 | 
				
			||||||
 | 
					            .dst_array_element(0)
 | 
				
			||||||
 | 
					            .descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
 | 
				
			||||||
 | 
					            .buffer_info(&buf_infos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let img_info = vk::DescriptorImageInfo::default()
 | 
				
			||||||
 | 
					            .image_layout(vk::ImageLayout::GENERAL)
 | 
				
			||||||
 | 
					            .image_view(skybox.0)
 | 
				
			||||||
 | 
					            .sampler(skybox.1);
 | 
				
			||||||
 | 
					        let img_infos = &[img_info];
 | 
				
			||||||
 | 
					        let img_desc = vk::WriteDescriptorSet::default()
 | 
				
			||||||
 | 
					            .dst_set(desc_set)
 | 
				
			||||||
 | 
					            .dst_binding(1)
 | 
				
			||||||
 | 
					            .dst_array_element(0)
 | 
				
			||||||
 | 
					            .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
 | 
				
			||||||
 | 
					            .image_info(img_infos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            ctx.dev.update_descriptor_sets(&[buf_desc, img_desc], &[]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn pipeline(&self) -> (vk::Pipeline, vk::PipelineLayout) {
 | 
				
			||||||
 | 
					        (self.pipeline, self.pipe_layout)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn push_constants(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        camera: &crate::game::Camera,
 | 
				
			||||||
 | 
					        res: [u32; 2],
 | 
				
			||||||
 | 
					        base_color: [f32; 4],
 | 
				
			||||||
 | 
					    ) -> Vec<(vk::ShaderStageFlags, u32, Vec<u8>)> {
 | 
				
			||||||
 | 
					        let mut constants = Vec::new();
 | 
				
			||||||
 | 
					        let cam_data: Vec<u8> = (Vec::<f32>::from([
 | 
				
			||||||
 | 
					            camera.origin.x,
 | 
				
			||||||
 | 
					            camera.origin.y,
 | 
				
			||||||
 | 
					            camera.origin.z,
 | 
				
			||||||
 | 
					            0.0,
 | 
				
			||||||
 | 
					            camera.rotation.x,
 | 
				
			||||||
 | 
					            camera.rotation.y,
 | 
				
			||||||
 | 
					            camera.rotation.z,
 | 
				
			||||||
 | 
					        ]))
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|f| f.to_ne_bytes())
 | 
				
			||||||
 | 
					        .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					        .into_flattened();
 | 
				
			||||||
 | 
					        constants.push((vk::ShaderStageFlags::VERTEX, 0, cam_data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let screen_res: Vec<u8> = res
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|f| f.to_ne_bytes())
 | 
				
			||||||
 | 
					            .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					            .into_flattened();
 | 
				
			||||||
 | 
					        constants.push((vk::ShaderStageFlags::VERTEX, 32, screen_res));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let base_color: Vec<u8> = (Vec::<f32>::from([0.0, 1.0, 1.0, 1.0]))
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|f| f.to_ne_bytes())
 | 
				
			||||||
 | 
					            .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					            .into_flattened();
 | 
				
			||||||
 | 
					        constants.push((vk::ShaderStageFlags::FRAGMENT, 48, base_color));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constants
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RenderCtx {
 | 
				
			||||||
 | 
					    fn create_cube(&self, pass: vk::RenderPass) -> Cube {
 | 
				
			||||||
 | 
					        let mesh_mem = self.mem_alloc(MemType::HostVisibile, MESH_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mesh_buf = self.alloc_buf(
 | 
				
			||||||
 | 
					            mesh_mem,
 | 
				
			||||||
 | 
					            MESH_SIZE,
 | 
				
			||||||
 | 
					            vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::STORAGE_BUFFER,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mesh_mem = self.buf_to_ptr(mesh_mem, mesh_buf);
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            std::ptr::copy(POSITIONS.as_ptr(), mesh_mem as *mut f32, POSITIONS.len());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pipe_layout = setup_pipe_layout(self);
 | 
				
			||||||
 | 
					        let pipeline = setup_pipeline(self, &pass, pipe_layout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Cube {
 | 
				
			||||||
 | 
					            mesh_buf,
 | 
				
			||||||
 | 
					            pipeline,
 | 
				
			||||||
 | 
					            pipe_layout,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Game<LoadingWorld> {
 | 
				
			||||||
 | 
					    pub fn create_cube(&self) -> Cube {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state: LoadingWorld { ctx, pass, .. },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        ctx.create_cube(*pass)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_cube_shaders(ctx: &RenderCtx) -> (vk::ShaderModule, vk::ShaderModule) {
 | 
				
			||||||
 | 
					    let shader_vert_shader = ctx.shader_mod_from_file(
 | 
				
			||||||
 | 
					        "shaders/shader_vert.spv",
 | 
				
			||||||
 | 
					        vk::ShaderModuleCreateFlags::empty(),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    let shader_frag_shader = ctx.shader_mod_from_file(
 | 
				
			||||||
 | 
					        "shaders/shader_rag.spv",
 | 
				
			||||||
 | 
					        vk::ShaderModuleCreateFlags::empty(),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (shader_vert_shader, shader_frag_shader)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_desc_layout(ctx: &RenderCtx) -> vk::DescriptorSetLayout {
 | 
				
			||||||
 | 
					    let storage_binding = vk::DescriptorSetLayoutBinding::default()
 | 
				
			||||||
 | 
					        .binding(0)
 | 
				
			||||||
 | 
					        .descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
 | 
				
			||||||
 | 
					        .descriptor_count(1)
 | 
				
			||||||
 | 
					        .stage_flags(vk::ShaderStageFlags::VERTEX);
 | 
				
			||||||
 | 
					    let image_binding = vk::DescriptorSetLayoutBinding::default()
 | 
				
			||||||
 | 
					        .binding(1)
 | 
				
			||||||
 | 
					        .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
 | 
				
			||||||
 | 
					        .descriptor_count(1)
 | 
				
			||||||
 | 
					        .stage_flags(vk::ShaderStageFlags::FRAGMENT);
 | 
				
			||||||
 | 
					    let layouts = [storage_binding, image_binding];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&layouts);
 | 
				
			||||||
 | 
					    let layout = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_descriptor_set_layout(&layout_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create descriptor set layout")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    layout
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_pipe_layout(ctx: &RenderCtx) -> vk::PipelineLayout {
 | 
				
			||||||
 | 
					    let layout = setup_desc_layout(ctx);
 | 
				
			||||||
 | 
					    let push_range: [vk::PushConstantRange; 2] = [
 | 
				
			||||||
 | 
					        vk::PushConstantRange::default()
 | 
				
			||||||
 | 
					            .stage_flags(vk::ShaderStageFlags::VERTEX)
 | 
				
			||||||
 | 
					            .offset(0)
 | 
				
			||||||
 | 
					            .size(48), // vec4 camera_orig, camera_rot; uvec2 screen_res
 | 
				
			||||||
 | 
					        vk::PushConstantRange::default()
 | 
				
			||||||
 | 
					            .stage_flags(vk::ShaderStageFlags::FRAGMENT)
 | 
				
			||||||
 | 
					            .offset(48)
 | 
				
			||||||
 | 
					            .size(16), // vec4 base_color
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let layouts = &[layout];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pipe_layout = vk::PipelineLayoutCreateInfo::default()
 | 
				
			||||||
 | 
					        .set_layouts(layouts.as_ref())
 | 
				
			||||||
 | 
					        .push_constant_ranges(&push_range);
 | 
				
			||||||
 | 
					    let pipe_layout = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_pipeline_layout(&pipe_layout, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create pipeline layout")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    pipe_layout
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_pipeline(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    pass: &vk::RenderPass,
 | 
				
			||||||
 | 
					    layout: vk::PipelineLayout,
 | 
				
			||||||
 | 
					) -> vk::Pipeline {
 | 
				
			||||||
 | 
					    let (vert_shader, frag_shader) = load_cube_shaders(ctx);
 | 
				
			||||||
 | 
					    let shader_stages = ctx.setup_simple_shader_stage(vert_shader, frag_shader);
 | 
				
			||||||
 | 
					    let vert_input = vk::PipelineVertexInputStateCreateInfo::default();
 | 
				
			||||||
 | 
					    let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .topology(vk::PrimitiveTopology::TRIANGLE_LIST);
 | 
				
			||||||
 | 
					    let rasterization = vk::PipelineRasterizationStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .polygon_mode(vk::PolygonMode::FILL)
 | 
				
			||||||
 | 
					        .cull_mode(vk::CullModeFlags::BACK)
 | 
				
			||||||
 | 
					        .front_face(vk::FrontFace::COUNTER_CLOCKWISE)
 | 
				
			||||||
 | 
					        .line_width(1.0);
 | 
				
			||||||
 | 
					    let multisample = vk::PipelineMultisampleStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .rasterization_samples(vk::SampleCountFlags::TYPE_1);
 | 
				
			||||||
 | 
					    let depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .depth_test_enable(true)
 | 
				
			||||||
 | 
					        .depth_write_enable(true)
 | 
				
			||||||
 | 
					        .depth_compare_op(vk::CompareOp::LESS)
 | 
				
			||||||
 | 
					        .depth_bounds_test_enable(true)
 | 
				
			||||||
 | 
					        .stencil_test_enable(false)
 | 
				
			||||||
 | 
					        .min_depth_bounds(0.0)
 | 
				
			||||||
 | 
					        .max_depth_bounds(1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let blend = vk::PipelineColorBlendAttachmentState::default()
 | 
				
			||||||
 | 
					        .src_color_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .dst_color_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .color_blend_op(vk::BlendOp::ADD)
 | 
				
			||||||
 | 
					        .src_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .dst_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .alpha_blend_op(vk::BlendOp::ADD)
 | 
				
			||||||
 | 
					        .color_write_mask(
 | 
				
			||||||
 | 
					            vk::ColorComponentFlags::R
 | 
				
			||||||
 | 
					                | vk::ColorComponentFlags::G
 | 
				
			||||||
 | 
					                | vk::ColorComponentFlags::B
 | 
				
			||||||
 | 
					                | vk::ColorComponentFlags::A,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let blend_attachments = [blend];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let color_blend = vk::PipelineColorBlendStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .attachments(blend_attachments.as_ref())
 | 
				
			||||||
 | 
					        .logic_op_enable(false)
 | 
				
			||||||
 | 
					        .logic_op(vk::LogicOp::COPY)
 | 
				
			||||||
 | 
					        .blend_constants([1.0, 1.0, 1.0, 1.0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let dynamic = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&[
 | 
				
			||||||
 | 
					        vk::DynamicState::VIEWPORT_WITH_COUNT,
 | 
				
			||||||
 | 
					        vk::DynamicState::SCISSOR_WITH_COUNT,
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pipe_info = vk::GraphicsPipelineCreateInfo::default()
 | 
				
			||||||
 | 
					        .stages(&shader_stages)
 | 
				
			||||||
 | 
					        .vertex_input_state(&vert_input)
 | 
				
			||||||
 | 
					        .input_assembly_state(&input_assembly)
 | 
				
			||||||
 | 
					        .rasterization_state(&rasterization)
 | 
				
			||||||
 | 
					        .multisample_state(&multisample)
 | 
				
			||||||
 | 
					        .depth_stencil_state(&depth_stencil)
 | 
				
			||||||
 | 
					        .color_blend_state(&color_blend)
 | 
				
			||||||
 | 
					        .layout(layout)
 | 
				
			||||||
 | 
					        .dynamic_state(&dynamic)
 | 
				
			||||||
 | 
					        .render_pass(*pass)
 | 
				
			||||||
 | 
					        .subpass(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pipe = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_graphics_pipelines(vk::PipelineCache::null(), &[pipe_info], None)
 | 
				
			||||||
 | 
					            .expect("Failed to create graphics pipeline")
 | 
				
			||||||
 | 
					            .remove(0)
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    println!("Created pipeline");
 | 
				
			||||||
 | 
					    pipe
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,284 @@
 | 
				
			|||||||
 | 
					use ash::vk::{self};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{Game, InWorld, RenderCtx, Window};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{
 | 
				
			||||||
 | 
					    SwapchainCtx,
 | 
				
			||||||
 | 
					    loading_world::{Component, WorldComponent as _},
 | 
				
			||||||
 | 
					    swapchain::{
 | 
				
			||||||
 | 
					        make_depth_img, make_depth_view, make_framebufs, make_swap_images, make_swap_views,
 | 
				
			||||||
 | 
					        setup_swapchain,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Game<InWorld> {
 | 
				
			||||||
 | 
					    pub fn window_resize(&mut self, size: (u32, u32)) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state:
 | 
				
			||||||
 | 
					                InWorld {
 | 
				
			||||||
 | 
					                    sdl_context,
 | 
				
			||||||
 | 
					                    window,
 | 
				
			||||||
 | 
					                    ctx,
 | 
				
			||||||
 | 
					                    skybox,
 | 
				
			||||||
 | 
					                    components,
 | 
				
			||||||
 | 
					                    sem_avail,
 | 
				
			||||||
 | 
					                    sem_finish,
 | 
				
			||||||
 | 
					                    fence_flight,
 | 
				
			||||||
 | 
					                    swapchain:
 | 
				
			||||||
 | 
					                        SwapchainCtx {
 | 
				
			||||||
 | 
					                            surface_loader,
 | 
				
			||||||
 | 
					                            swapchain_loader,
 | 
				
			||||||
 | 
					                            swap_images,
 | 
				
			||||||
 | 
					                            swap_views,
 | 
				
			||||||
 | 
					                            depth_mem,
 | 
				
			||||||
 | 
					                            depth_image,
 | 
				
			||||||
 | 
					                            depth_view,
 | 
				
			||||||
 | 
					                            framebufs,
 | 
				
			||||||
 | 
					                            swapchain,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    pass,
 | 
				
			||||||
 | 
					                    camera,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        window.width = size.0;
 | 
				
			||||||
 | 
					        window.height = size.1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            ctx.dev
 | 
				
			||||||
 | 
					                .device_wait_idle()
 | 
				
			||||||
 | 
					                .expect("Failed to wait for device idle");
 | 
				
			||||||
 | 
					            swapchain_loader.destroy_swapchain(*swapchain, None);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        (*swapchain, _) = setup_swapchain(
 | 
				
			||||||
 | 
					            &ctx,
 | 
				
			||||||
 | 
					            &surface_loader,
 | 
				
			||||||
 | 
					            &swapchain_loader,
 | 
				
			||||||
 | 
					            window.width,
 | 
				
			||||||
 | 
					            window.height,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        *swap_images = make_swap_images(*swapchain, swapchain_loader);
 | 
				
			||||||
 | 
					        *swap_views = make_swap_views(&ctx, &swap_images, vk::Format::B8G8R8A8_UNORM);
 | 
				
			||||||
 | 
					        *depth_image = make_depth_img(&ctx, window.width, window.height, *depth_mem);
 | 
				
			||||||
 | 
					        *depth_view = make_depth_view(&ctx, *depth_image, vk::Format::D32_SFLOAT);
 | 
				
			||||||
 | 
					        *framebufs = make_framebufs(
 | 
				
			||||||
 | 
					            &ctx,
 | 
				
			||||||
 | 
					            &swap_views,
 | 
				
			||||||
 | 
					            &depth_view,
 | 
				
			||||||
 | 
					            &pass,
 | 
				
			||||||
 | 
					            window.width,
 | 
				
			||||||
 | 
					            window.height,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn render_frame(&self) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state:
 | 
				
			||||||
 | 
					                InWorld {
 | 
				
			||||||
 | 
					                    sdl_context,
 | 
				
			||||||
 | 
					                    window,
 | 
				
			||||||
 | 
					                    ctx,
 | 
				
			||||||
 | 
					                    skybox,
 | 
				
			||||||
 | 
					                    components,
 | 
				
			||||||
 | 
					                    sem_avail,
 | 
				
			||||||
 | 
					                    sem_finish,
 | 
				
			||||||
 | 
					                    fence_flight,
 | 
				
			||||||
 | 
					                    swapchain,
 | 
				
			||||||
 | 
					                    pass,
 | 
				
			||||||
 | 
					                    camera,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.wait_for_fence(*fence_flight);
 | 
				
			||||||
 | 
					        ctx.reset_fence(*fence_flight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let img_idx = ack_next_img(swapchain, sem_avail);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.start_cmd_buf();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.record_commands(img_idx as usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.end_cmd_buf();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.submit_queue(*sem_avail, *sem_finish, *fence_flight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx.queue_present(swapchain, img_idx, *sem_finish);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn record_commands(&self, img_idx: usize) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state:
 | 
				
			||||||
 | 
					                InWorld {
 | 
				
			||||||
 | 
					                    sdl_context,
 | 
				
			||||||
 | 
					                    window: Window { width, height },
 | 
				
			||||||
 | 
					                    ctx: RenderCtx { dev, cmd_buf, .. },
 | 
				
			||||||
 | 
					                    skybox,
 | 
				
			||||||
 | 
					                    components,
 | 
				
			||||||
 | 
					                    swapchain,
 | 
				
			||||||
 | 
					                    pass,
 | 
				
			||||||
 | 
					                    camera,
 | 
				
			||||||
 | 
					                    ..
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let clear_vals = [
 | 
				
			||||||
 | 
					            vk::ClearValue {
 | 
				
			||||||
 | 
					                color: vk::ClearColorValue {
 | 
				
			||||||
 | 
					                    float32: [0.0, 0.0, 0.0, 1.0],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            vk::ClearValue {
 | 
				
			||||||
 | 
					                depth_stencil: vk::ClearDepthStencilValue {
 | 
				
			||||||
 | 
					                    depth: 1.0,
 | 
				
			||||||
 | 
					                    stencil: 0,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let render_pass_info = vk::RenderPassBeginInfo::default()
 | 
				
			||||||
 | 
					            .render_pass(*pass)
 | 
				
			||||||
 | 
					            .framebuffer(swapchain.framebufs[img_idx])
 | 
				
			||||||
 | 
					            .render_area(
 | 
				
			||||||
 | 
					                vk::Rect2D::default()
 | 
				
			||||||
 | 
					                    .offset(vk::Offset2D::default())
 | 
				
			||||||
 | 
					                    .extent(vk::Extent2D {
 | 
				
			||||||
 | 
					                        width: *width,
 | 
				
			||||||
 | 
					                        height: *height,
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .clear_values(&clear_vals);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let regions = (0..6)
 | 
				
			||||||
 | 
					                .map(|i| {
 | 
				
			||||||
 | 
					                    vk::BufferImageCopy::default()
 | 
				
			||||||
 | 
					                        .buffer_offset(3 * 2048 * 2048 * i)
 | 
				
			||||||
 | 
					                        .buffer_row_length(0)
 | 
				
			||||||
 | 
					                        .buffer_image_height(0)
 | 
				
			||||||
 | 
					                        .image_offset(vk::Offset3D::default())
 | 
				
			||||||
 | 
					                        .image_extent(vk::Extent3D::default().width(2048).height(2048).depth(1))
 | 
				
			||||||
 | 
					                        .image_subresource(
 | 
				
			||||||
 | 
					                            vk::ImageSubresourceLayers::default()
 | 
				
			||||||
 | 
					                                .aspect_mask(vk::ImageAspectFlags::COLOR)
 | 
				
			||||||
 | 
					                                .mip_level(0)
 | 
				
			||||||
 | 
					                                .layer_count(1)
 | 
				
			||||||
 | 
					                                .base_array_layer(i as u32),
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					            dev.cmd_copy_buffer_to_image(
 | 
				
			||||||
 | 
					                *cmd_buf,
 | 
				
			||||||
 | 
					                skybox.0.buf,
 | 
				
			||||||
 | 
					                skybox.0.image,
 | 
				
			||||||
 | 
					                vk::ImageLayout::GENERAL,
 | 
				
			||||||
 | 
					                ®ions,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            dev.cmd_begin_render_pass(*cmd_buf, &render_pass_info, vk::SubpassContents::INLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let base_color = [0.0, 1.0, 1.0, 1.0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for Component { inner, desc_set } in components {
 | 
				
			||||||
 | 
					                let (pipe, layout) = inner.pipeline();
 | 
				
			||||||
 | 
					                dev.cmd_bind_pipeline(*cmd_buf, vk::PipelineBindPoint::GRAPHICS, pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let desc_sets = [*desc_set];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dev.cmd_bind_descriptor_sets(
 | 
				
			||||||
 | 
					                    *cmd_buf,
 | 
				
			||||||
 | 
					                    vk::PipelineBindPoint::GRAPHICS,
 | 
				
			||||||
 | 
					                    layout,
 | 
				
			||||||
 | 
					                    0,
 | 
				
			||||||
 | 
					                    desc_sets.as_ref(),
 | 
				
			||||||
 | 
					                    &[],
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dev.cmd_set_viewport_with_count(
 | 
				
			||||||
 | 
					                    *cmd_buf,
 | 
				
			||||||
 | 
					                    &[vk::Viewport::default()
 | 
				
			||||||
 | 
					                        .width(*width as f32)
 | 
				
			||||||
 | 
					                        .height(*height as f32)],
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                dev.cmd_set_scissor_with_count(
 | 
				
			||||||
 | 
					                    *cmd_buf,
 | 
				
			||||||
 | 
					                    &[vk::Rect2D::default().extent(vk::Extent2D {
 | 
				
			||||||
 | 
					                        width: *width,
 | 
				
			||||||
 | 
					                        height: *height,
 | 
				
			||||||
 | 
					                    })],
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                inner
 | 
				
			||||||
 | 
					                    .push_constants(camera, [*width, *height], base_color)
 | 
				
			||||||
 | 
					                    .into_iter()
 | 
				
			||||||
 | 
					                    .for_each(|(f, o, d)| {
 | 
				
			||||||
 | 
					                        dev.cmd_push_constants(
 | 
				
			||||||
 | 
					                            *cmd_buf,
 | 
				
			||||||
 | 
					                            layout,
 | 
				
			||||||
 | 
					                            vk::ShaderStageFlags::VERTEX,
 | 
				
			||||||
 | 
					                            0,
 | 
				
			||||||
 | 
					                            d.as_ref(),
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dev.cmd_draw(*cmd_buf, 36, 1, 0, 0);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                let (pipe, layout) = skybox.0.pipeline();
 | 
				
			||||||
 | 
					                dev.cmd_bind_pipeline(*cmd_buf, vk::PipelineBindPoint::GRAPHICS, pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let desc_sets = [skybox.1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dev.cmd_bind_descriptor_sets(
 | 
				
			||||||
 | 
					                    *cmd_buf,
 | 
				
			||||||
 | 
					                    vk::PipelineBindPoint::GRAPHICS,
 | 
				
			||||||
 | 
					                    layout,
 | 
				
			||||||
 | 
					                    0,
 | 
				
			||||||
 | 
					                    desc_sets.as_ref(),
 | 
				
			||||||
 | 
					                    &[],
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dev.cmd_set_viewport_with_count(
 | 
				
			||||||
 | 
					                    *cmd_buf,
 | 
				
			||||||
 | 
					                    &[vk::Viewport::default()
 | 
				
			||||||
 | 
					                        .width(*width as f32)
 | 
				
			||||||
 | 
					                        .height(*height as f32)],
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                dev.cmd_set_scissor_with_count(
 | 
				
			||||||
 | 
					                    *cmd_buf,
 | 
				
			||||||
 | 
					                    &[vk::Rect2D::default().extent(vk::Extent2D {
 | 
				
			||||||
 | 
					                        width: *width,
 | 
				
			||||||
 | 
					                        height: *height,
 | 
				
			||||||
 | 
					                    })],
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                skybox
 | 
				
			||||||
 | 
					                    .0
 | 
				
			||||||
 | 
					                    .push_constants(camera, [*width, *height], base_color)
 | 
				
			||||||
 | 
					                    .into_iter()
 | 
				
			||||||
 | 
					                    .for_each(|(f, o, d)| {
 | 
				
			||||||
 | 
					                        dev.cmd_push_constants(
 | 
				
			||||||
 | 
					                            *cmd_buf,
 | 
				
			||||||
 | 
					                            layout,
 | 
				
			||||||
 | 
					                            vk::ShaderStageFlags::VERTEX,
 | 
				
			||||||
 | 
					                            0,
 | 
				
			||||||
 | 
					                            d.as_ref(),
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dev.cmd_draw(*cmd_buf, 36, 1, 0, 0);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dev.cmd_end_render_pass(*cmd_buf);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn ack_next_img(swapchain: &SwapchainCtx, sem_avail: &vk::Semaphore) -> u32 {
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        let (img_inx, _) = swapchain
 | 
				
			||||||
 | 
					            .swapchain_loader
 | 
				
			||||||
 | 
					            .acquire_next_image(swapchain.swapchain, u64::MAX, *sem_avail, vk::Fence::null())
 | 
				
			||||||
 | 
					            .expect("Failed to acquire next image");
 | 
				
			||||||
 | 
					        img_inx
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,250 @@
 | 
				
			|||||||
 | 
					use std::ffi::{CStr, CString};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ash::{
 | 
				
			||||||
 | 
					    Device, Entry, Instance,
 | 
				
			||||||
 | 
					    khr::surface,
 | 
				
			||||||
 | 
					    vk::{self},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _};
 | 
				
			||||||
 | 
					use sdl2::{Sdl, video::Window};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{APP_NAME, Game, RenderAvailable, RenderCtx, Unstarted};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Game<Unstarted> {
 | 
				
			||||||
 | 
					    pub fn init_render(self, sdl_context: Sdl, window: Window) -> Game<RenderAvailable> {
 | 
				
			||||||
 | 
					        let (width, height) = window.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let entry = Entry::linked();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let instance = create_instance(&window, &entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let surface = make_surface(&entry, &instance, &window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pdev = find_pdev_dgpu(&instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let queue_idx = find_rcs_queue_inx(&instance, &pdev).expect("No RCS queue found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let dev = make_dev(
 | 
				
			||||||
 | 
					            &instance,
 | 
				
			||||||
 | 
					            &pdev,
 | 
				
			||||||
 | 
					            queue_idx,
 | 
				
			||||||
 | 
					            vec![c"VK_KHR_swapchain", c"VK_EXT_extended_dynamic_state3"],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let queue = unsafe { dev.get_device_queue(queue_idx, 0) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let cmd_pool = make_command_pool(&dev, queue_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let cmd_buf = alloc_cmd_buf(&dev, cmd_pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let host_vis_idx =
 | 
				
			||||||
 | 
					            find_host_visible(&instance, &pdev).expect("No host visible memory found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let host_invis_idx =
 | 
				
			||||||
 | 
					            find_host_invisible(&instance, &pdev).expect("No host invisible memory found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let surface_loader = surface::Instance::new(&entry, &instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Game {
 | 
				
			||||||
 | 
					            state: RenderAvailable {
 | 
				
			||||||
 | 
					                sdl_context,
 | 
				
			||||||
 | 
					                window: crate::Window { width, height },
 | 
				
			||||||
 | 
					                ctx: RenderCtx {
 | 
				
			||||||
 | 
					                    entry,
 | 
				
			||||||
 | 
					                    instance,
 | 
				
			||||||
 | 
					                    pdev,
 | 
				
			||||||
 | 
					                    dev,
 | 
				
			||||||
 | 
					                    surface,
 | 
				
			||||||
 | 
					                    surface_loader,
 | 
				
			||||||
 | 
					                    queue,
 | 
				
			||||||
 | 
					                    queue_idx,
 | 
				
			||||||
 | 
					                    cmd_buf,
 | 
				
			||||||
 | 
					                    host_vis_idx,
 | 
				
			||||||
 | 
					                    host_invis_idx,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn create_instance(window: &Window, entry: &Entry) -> Instance {
 | 
				
			||||||
 | 
					    let n_app_name = CString::new(APP_NAME).unwrap();
 | 
				
			||||||
 | 
					    let n_engine_name = CString::new(format!("{} Engine", APP_NAME)).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let appinfo = vk::ApplicationInfo::default()
 | 
				
			||||||
 | 
					        .application_name(n_app_name.as_c_str())
 | 
				
			||||||
 | 
					        .application_version(0)
 | 
				
			||||||
 | 
					        .engine_name(n_engine_name.as_c_str())
 | 
				
			||||||
 | 
					        .engine_version(0)
 | 
				
			||||||
 | 
					        .api_version(vk::make_api_version(0, 1, 3, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let default_exts = window
 | 
				
			||||||
 | 
					        .vulkan_instance_extensions()
 | 
				
			||||||
 | 
					        .expect("Failed to get list of required extensions from SDL2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut exts = vec![];
 | 
				
			||||||
 | 
					    exts.extend(default_exts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let exts: Vec<*const i8> = exts
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|s| s.as_ptr() as *const i8)
 | 
				
			||||||
 | 
					        .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					    let exts: &[*const i8] = exts.as_slice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let insinfo = vk::InstanceCreateInfo::default()
 | 
				
			||||||
 | 
					        .application_info(&appinfo)
 | 
				
			||||||
 | 
					        .enabled_extension_names(exts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let instance =
 | 
				
			||||||
 | 
					        unsafe { entry.create_instance(&insinfo, None) }.expect("Failed to create instance");
 | 
				
			||||||
 | 
					    println!("Created instance");
 | 
				
			||||||
 | 
					    instance
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_surface(entry: &Entry, instance: &Instance, window: &Window) -> vk::SurfaceKHR {
 | 
				
			||||||
 | 
					    let surface = unsafe {
 | 
				
			||||||
 | 
					        ash_window::create_surface(
 | 
				
			||||||
 | 
					            &entry,
 | 
				
			||||||
 | 
					            &instance,
 | 
				
			||||||
 | 
					            window.display_handle().unwrap().as_raw(),
 | 
				
			||||||
 | 
					            window.window_handle().unwrap().as_raw(),
 | 
				
			||||||
 | 
					            None,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .expect("Failed to create surface");
 | 
				
			||||||
 | 
					    println!("Created surface");
 | 
				
			||||||
 | 
					    surface
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn find_pdev_dgpu(instance: &Instance) -> vk::PhysicalDevice {
 | 
				
			||||||
 | 
					    let mut pdevs =
 | 
				
			||||||
 | 
					        unsafe { instance.enumerate_physical_devices() }.expect("Failed to enumerate devices");
 | 
				
			||||||
 | 
					    for (i, d) in pdevs.iter().enumerate() {
 | 
				
			||||||
 | 
					        let props = unsafe { instance.get_physical_device_properties(*d) };
 | 
				
			||||||
 | 
					        if props.device_type == vk::PhysicalDeviceType::DISCRETE_GPU {
 | 
				
			||||||
 | 
					            // TODO this assumes that the first discrete GPU will have an RCS queue family
 | 
				
			||||||
 | 
					            // This is not guaranteed by the spec (example, a compute-only GPU)
 | 
				
			||||||
 | 
					            // Fix.
 | 
				
			||||||
 | 
					            println!(
 | 
				
			||||||
 | 
					                "Found discrete GPU: {}",
 | 
				
			||||||
 | 
					                unsafe { std::str::from_utf8(std::mem::transmute(props.device_name.as_slice())) }
 | 
				
			||||||
 | 
					                    .unwrap()
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return pdevs.remove(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    println!("No discrete GPU found");
 | 
				
			||||||
 | 
					    assert!(pdevs.len() > 0, "No GPU found");
 | 
				
			||||||
 | 
					    return pdevs.remove(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Using Intel GPU hardware terminology 🥴
 | 
				
			||||||
 | 
					fn find_rcs_queue_inx(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option<u32> {
 | 
				
			||||||
 | 
					    let qfams = unsafe { instance.get_physical_device_queue_family_properties(*pdev) };
 | 
				
			||||||
 | 
					    for (inx, qfam) in qfams.iter().enumerate() {
 | 
				
			||||||
 | 
					        if qfam
 | 
				
			||||||
 | 
					            .queue_flags
 | 
				
			||||||
 | 
					            .contains(vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            println!("Found RCS queue at index {}", inx);
 | 
				
			||||||
 | 
					            return Some(inx as u32);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    println!("No RCS queue found");
 | 
				
			||||||
 | 
					    return None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_dev(
 | 
				
			||||||
 | 
					    instance: &Instance,
 | 
				
			||||||
 | 
					    pdev: &vk::PhysicalDevice,
 | 
				
			||||||
 | 
					    rcs_queue_inx: u32,
 | 
				
			||||||
 | 
					    exts: Vec<&CStr>,
 | 
				
			||||||
 | 
					) -> Device {
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        let dev_queue = vec![
 | 
				
			||||||
 | 
					            vk::DeviceQueueCreateInfo::default()
 | 
				
			||||||
 | 
					                .queue_family_index(rcs_queue_inx)
 | 
				
			||||||
 | 
					                .queue_priorities(&[1.0]),
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let exts = exts.iter().map(|&s| s.as_ptr()).collect::<Vec<_>>();
 | 
				
			||||||
 | 
					        let exts = exts.as_slice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Enable all features
 | 
				
			||||||
 | 
					        let features = instance.get_physical_device_features(*pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let dev_info = vk::DeviceCreateInfo::default()
 | 
				
			||||||
 | 
					            .queue_create_infos(&dev_queue)
 | 
				
			||||||
 | 
					            .enabled_extension_names(exts)
 | 
				
			||||||
 | 
					            .enabled_features(&features);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let dev = instance
 | 
				
			||||||
 | 
					            .create_device(*pdev, &dev_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create device");
 | 
				
			||||||
 | 
					        println!("Created device");
 | 
				
			||||||
 | 
					        dev
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_command_pool(dev: &Device, rcs_queue_inx: u32) -> vk::CommandPool {
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        let pool_info = vk::CommandPoolCreateInfo::default()
 | 
				
			||||||
 | 
					            .queue_family_index(rcs_queue_inx)
 | 
				
			||||||
 | 
					            .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER);
 | 
				
			||||||
 | 
					        let pool = dev
 | 
				
			||||||
 | 
					            .create_command_pool(&pool_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create command pool");
 | 
				
			||||||
 | 
					        println!("Created command pool");
 | 
				
			||||||
 | 
					        pool
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn alloc_cmd_buf(dev: &Device, pool: vk::CommandPool) -> vk::CommandBuffer {
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        let alloc_info = vk::CommandBufferAllocateInfo::default()
 | 
				
			||||||
 | 
					            .command_pool(pool)
 | 
				
			||||||
 | 
					            .level(vk::CommandBufferLevel::PRIMARY)
 | 
				
			||||||
 | 
					            .command_buffer_count(1);
 | 
				
			||||||
 | 
					        let cmd_buf = dev
 | 
				
			||||||
 | 
					            .allocate_command_buffers(&alloc_info)
 | 
				
			||||||
 | 
					            .expect("Failed to allocate command buffer")
 | 
				
			||||||
 | 
					            .remove(0);
 | 
				
			||||||
 | 
					        println!("Allocated command buffer");
 | 
				
			||||||
 | 
					        cmd_buf
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn find_host_visible(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option<u32> {
 | 
				
			||||||
 | 
					    let mem_props = unsafe { instance.get_physical_device_memory_properties(*pdev) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i, mem_type) in mem_props.memory_types.iter().enumerate() {
 | 
				
			||||||
 | 
					        if mem_type.property_flags.contains(
 | 
				
			||||||
 | 
					            vk::MemoryPropertyFlags::DEVICE_LOCAL
 | 
				
			||||||
 | 
					                | vk::MemoryPropertyFlags::HOST_VISIBLE
 | 
				
			||||||
 | 
					                | vk::MemoryPropertyFlags::HOST_COHERENT,
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            println!("Found host visible memory at index {}", i);
 | 
				
			||||||
 | 
					            return Some(i as u32);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    println!("No host visible memory found");
 | 
				
			||||||
 | 
					    return None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn find_host_invisible(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option<u32> {
 | 
				
			||||||
 | 
					    let mem_props = unsafe { instance.get_physical_device_memory_properties(*pdev) };
 | 
				
			||||||
 | 
					    for (i, mem_type) in mem_props.memory_types.iter().enumerate() {
 | 
				
			||||||
 | 
					        if mem_type
 | 
				
			||||||
 | 
					            .property_flags
 | 
				
			||||||
 | 
					            .contains(vk::MemoryPropertyFlags::DEVICE_LOCAL)
 | 
				
			||||||
 | 
					            && !mem_type.property_flags.contains(
 | 
				
			||||||
 | 
					                vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            println!("Found host invisible memory at index {}", i);
 | 
				
			||||||
 | 
					            return Some(i as u32);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    println!("No host invisible memory found");
 | 
				
			||||||
 | 
					    return None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					use std::{collections::HashMap, iter};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ash::{
 | 
				
			||||||
 | 
					    khr::{surface, swapchain},
 | 
				
			||||||
 | 
					    vk::{self, DescriptorSet},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    Game, InWorld, LoadingWorld, RenderAvailable, RenderCtx, game::Camera, render::MemType,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{
 | 
				
			||||||
 | 
					    MAX_HEIGHT, MAX_WIDTH, SwapchainCtx,
 | 
				
			||||||
 | 
					    swapchain::{
 | 
				
			||||||
 | 
					        make_depth_img, make_depth_view, make_framebufs, make_swap_images, make_swap_views,
 | 
				
			||||||
 | 
					        setup_swapchain,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Anything can be rendered in world
 | 
				
			||||||
 | 
					pub trait WorldComponent {
 | 
				
			||||||
 | 
					    fn descriptors(&self) -> HashMap<vk::DescriptorType, u32>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn desc_layout(&self, ctx: &RenderCtx) -> vk::DescriptorSetLayout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Skybox is passed in for reflections
 | 
				
			||||||
 | 
					    fn write_desc_set(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        ctx: &RenderCtx,
 | 
				
			||||||
 | 
					        desc_set: vk::DescriptorSet,
 | 
				
			||||||
 | 
					        skybox: (vk::ImageView, vk::Sampler),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn pipeline(&self) -> (vk::Pipeline, vk::PipelineLayout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn push_constants(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        camera: &Camera,
 | 
				
			||||||
 | 
					        res: [u32; 2],
 | 
				
			||||||
 | 
					        base_color: [f32; 4],
 | 
				
			||||||
 | 
					    ) -> Vec<(vk::ShaderStageFlags, u32, Vec<u8>)>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Component {
 | 
				
			||||||
 | 
					    pub inner: Box<dyn WorldComponent>,
 | 
				
			||||||
 | 
					    pub desc_set: DescriptorSet,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Game<RenderAvailable> {
 | 
				
			||||||
 | 
					    pub fn start_load_world(self) -> Game<LoadingWorld> {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state:
 | 
				
			||||||
 | 
					                RenderAvailable {
 | 
				
			||||||
 | 
					                    sdl_context,
 | 
				
			||||||
 | 
					                    ctx,
 | 
				
			||||||
 | 
					                    window,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let depth_mem = ctx.mem_alloc(MemType::HostInvisible, (MAX_WIDTH * MAX_HEIGHT * 8) as u64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pass = setup_render_pass(&ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let surface_loader = surface::Instance::new(&ctx.entry, &ctx.instance);
 | 
				
			||||||
 | 
					        let swapchain_loader = swapchain::Device::new(&ctx.instance, &ctx.dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let (swapchain, extents) = setup_swapchain(
 | 
				
			||||||
 | 
					            &ctx,
 | 
				
			||||||
 | 
					            &surface_loader,
 | 
				
			||||||
 | 
					            &swapchain_loader,
 | 
				
			||||||
 | 
					            window.width,
 | 
				
			||||||
 | 
					            window.height,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let depth_img = make_depth_img(&ctx, window.width, window.height, depth_mem);
 | 
				
			||||||
 | 
					        let swap_images = make_swap_images(swapchain, &swapchain_loader);
 | 
				
			||||||
 | 
					        let swap_views = make_swap_views(&ctx, &swap_images, vk::Format::B8G8R8A8_UNORM);
 | 
				
			||||||
 | 
					        let depth_view = make_depth_view(&ctx, depth_img, vk::Format::D32_SFLOAT);
 | 
				
			||||||
 | 
					        let framebufs = make_framebufs(
 | 
				
			||||||
 | 
					            &ctx,
 | 
				
			||||||
 | 
					            &swap_views,
 | 
				
			||||||
 | 
					            &depth_view,
 | 
				
			||||||
 | 
					            &pass,
 | 
				
			||||||
 | 
					            window.width,
 | 
				
			||||||
 | 
					            window.height,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let skybox = ctx.create_skybox(pass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let requested_descriptors = skybox.descriptors();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Game {
 | 
				
			||||||
 | 
					            state: LoadingWorld {
 | 
				
			||||||
 | 
					                sdl_context,
 | 
				
			||||||
 | 
					                ctx,
 | 
				
			||||||
 | 
					                window,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                requested_descriptors,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                swapchain: SwapchainCtx {
 | 
				
			||||||
 | 
					                    surface_loader,
 | 
				
			||||||
 | 
					                    swapchain_loader,
 | 
				
			||||||
 | 
					                    swap_images,
 | 
				
			||||||
 | 
					                    swap_views,
 | 
				
			||||||
 | 
					                    depth_mem,
 | 
				
			||||||
 | 
					                    depth_image: depth_img,
 | 
				
			||||||
 | 
					                    depth_view,
 | 
				
			||||||
 | 
					                    framebufs,
 | 
				
			||||||
 | 
					                    swapchain,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                pass,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                skybox,
 | 
				
			||||||
 | 
					                components: Vec::new(),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Game<LoadingWorld> {
 | 
				
			||||||
 | 
					    pub fn add_component<C: WorldComponent + 'static>(&mut self, component: C) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state:
 | 
				
			||||||
 | 
					                LoadingWorld {
 | 
				
			||||||
 | 
					                    requested_descriptors,
 | 
				
			||||||
 | 
					                    components,
 | 
				
			||||||
 | 
					                    ..
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        for (desc, n) in component.descriptors() {
 | 
				
			||||||
 | 
					            match requested_descriptors.remove(&desc) {
 | 
				
			||||||
 | 
					                Some(m) => requested_descriptors.insert(desc, n + m),
 | 
				
			||||||
 | 
					                None => requested_descriptors.insert(desc, n),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        components.push(Box::new(component));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn start_world(self) -> Game<InWorld> {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            state:
 | 
				
			||||||
 | 
					                LoadingWorld {
 | 
				
			||||||
 | 
					                    sdl_context,
 | 
				
			||||||
 | 
					                    window,
 | 
				
			||||||
 | 
					                    ctx,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    requested_descriptors,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    swapchain,
 | 
				
			||||||
 | 
					                    pass,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    skybox,
 | 
				
			||||||
 | 
					                    components,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        let desc_pool = setup_desc_pool(&ctx, requested_descriptors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut desc_sets = make_desc_sets(
 | 
				
			||||||
 | 
					            &ctx,
 | 
				
			||||||
 | 
					            &desc_pool,
 | 
				
			||||||
 | 
					            &components
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .map(|c| c.desc_layout(&ctx))
 | 
				
			||||||
 | 
					                .chain(iter::once(skybox.desc_layout(&ctx)))
 | 
				
			||||||
 | 
					                .collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let skybox_descriptor = desc_sets.pop().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let components = components
 | 
				
			||||||
 | 
					            .into_iter()
 | 
				
			||||||
 | 
					            .zip(desc_sets.into_iter())
 | 
				
			||||||
 | 
					            .map(|(c, d)| Component {
 | 
				
			||||||
 | 
					                inner: c,
 | 
				
			||||||
 | 
					                desc_set: d,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for comp in &components {
 | 
				
			||||||
 | 
					            let Component { inner, desc_set } = comp;
 | 
				
			||||||
 | 
					            inner.write_desc_set(&ctx, *desc_set, (skybox.imageview, skybox.sampler));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        skybox.write_desc_set(&ctx, skybox_descriptor, (skybox.imageview, skybox.sampler));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let sem_avail = ctx.make_sem();
 | 
				
			||||||
 | 
					        let sem_finish = ctx.make_sem();
 | 
				
			||||||
 | 
					        let fence_flight = ctx.make_fence();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Game {
 | 
				
			||||||
 | 
					            state: InWorld {
 | 
				
			||||||
 | 
					                sdl_context,
 | 
				
			||||||
 | 
					                window,
 | 
				
			||||||
 | 
					                ctx,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                skybox: (skybox, skybox_descriptor),
 | 
				
			||||||
 | 
					                components,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sem_avail,
 | 
				
			||||||
 | 
					                sem_finish,
 | 
				
			||||||
 | 
					                fence_flight,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                swapchain,
 | 
				
			||||||
 | 
					                pass,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                camera: Camera::default(),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_render_pass(ctx: &RenderCtx) -> vk::RenderPass {
 | 
				
			||||||
 | 
					    let color_attach = vk::AttachmentDescription::default()
 | 
				
			||||||
 | 
					        .format(vk::Format::B8G8R8A8_UNORM)
 | 
				
			||||||
 | 
					        .samples(vk::SampleCountFlags::TYPE_1)
 | 
				
			||||||
 | 
					        .load_op(vk::AttachmentLoadOp::CLEAR)
 | 
				
			||||||
 | 
					        .store_op(vk::AttachmentStoreOp::STORE)
 | 
				
			||||||
 | 
					        .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
 | 
				
			||||||
 | 
					        .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
 | 
				
			||||||
 | 
					        .initial_layout(vk::ImageLayout::UNDEFINED)
 | 
				
			||||||
 | 
					        .final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
 | 
				
			||||||
 | 
					    let depth_attach = vk::AttachmentDescription::default()
 | 
				
			||||||
 | 
					        .format(vk::Format::D32_SFLOAT)
 | 
				
			||||||
 | 
					        .samples(vk::SampleCountFlags::TYPE_1)
 | 
				
			||||||
 | 
					        .load_op(vk::AttachmentLoadOp::CLEAR)
 | 
				
			||||||
 | 
					        .store_op(vk::AttachmentStoreOp::DONT_CARE)
 | 
				
			||||||
 | 
					        .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
 | 
				
			||||||
 | 
					        .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
 | 
				
			||||||
 | 
					        .initial_layout(vk::ImageLayout::UNDEFINED)
 | 
				
			||||||
 | 
					        .final_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let color_ref = vk::AttachmentReference::default()
 | 
				
			||||||
 | 
					        .attachment(0)
 | 
				
			||||||
 | 
					        .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let depth_ref = vk::AttachmentReference::default()
 | 
				
			||||||
 | 
					        .attachment(1)
 | 
				
			||||||
 | 
					        .layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let color_refs = [color_ref];
 | 
				
			||||||
 | 
					    let depth_refs = [depth_ref];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let subpass = vk::SubpassDescription::default()
 | 
				
			||||||
 | 
					        .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
 | 
				
			||||||
 | 
					        .color_attachments(color_refs.as_ref())
 | 
				
			||||||
 | 
					        .depth_stencil_attachment(&depth_ref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let subpass_dep = vk::SubpassDependency::default()
 | 
				
			||||||
 | 
					        .src_subpass(vk::SUBPASS_EXTERNAL)
 | 
				
			||||||
 | 
					        .dst_subpass(0)
 | 
				
			||||||
 | 
					        .src_stage_mask(
 | 
				
			||||||
 | 
					            vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
 | 
				
			||||||
 | 
					                | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .dst_stage_mask(
 | 
				
			||||||
 | 
					            vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
 | 
				
			||||||
 | 
					                | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .src_access_mask(vk::AccessFlags::empty())
 | 
				
			||||||
 | 
					        .dst_access_mask(
 | 
				
			||||||
 | 
					            vk::AccessFlags::COLOR_ATTACHMENT_WRITE
 | 
				
			||||||
 | 
					                | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let attach_desc = [color_attach, depth_attach];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let subpasses = [subpass];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let deps = [subpass_dep];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pass_info = vk::RenderPassCreateInfo::default()
 | 
				
			||||||
 | 
					        .attachments(&attach_desc)
 | 
				
			||||||
 | 
					        .subpasses(subpasses.as_ref())
 | 
				
			||||||
 | 
					        .dependencies(deps.as_ref());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pass = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_render_pass(&pass_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create render pass")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_desc_pool(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    requested_descriptors: HashMap<vk::DescriptorType, u32>,
 | 
				
			||||||
 | 
					) -> vk::DescriptorPool {
 | 
				
			||||||
 | 
					    let pool_sizes = requested_descriptors
 | 
				
			||||||
 | 
					        .into_iter()
 | 
				
			||||||
 | 
					        .map(|(desc, count)| {
 | 
				
			||||||
 | 
					            vk::DescriptorPoolSize::default()
 | 
				
			||||||
 | 
					                .ty(desc)
 | 
				
			||||||
 | 
					                .descriptor_count(count)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pool_info = vk::DescriptorPoolCreateInfo::default()
 | 
				
			||||||
 | 
					        .max_sets(1)
 | 
				
			||||||
 | 
					        .pool_sizes(&pool_sizes);
 | 
				
			||||||
 | 
					    let pool = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_descriptor_pool(&pool_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create descriptor pool")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    pool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_desc_sets(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    desc_pool: &vk::DescriptorPool,
 | 
				
			||||||
 | 
					    layouts: &[vk::DescriptorSetLayout],
 | 
				
			||||||
 | 
					) -> Vec<vk::DescriptorSet> {
 | 
				
			||||||
 | 
					    let alloc_info = vk::DescriptorSetAllocateInfo::default()
 | 
				
			||||||
 | 
					        .descriptor_pool(*desc_pool)
 | 
				
			||||||
 | 
					        .set_layouts(&layouts);
 | 
				
			||||||
 | 
					    let sets = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .allocate_descriptor_sets(&alloc_info)
 | 
				
			||||||
 | 
					            .expect("Failed to allocate descriptor sets")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    sets
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,210 @@
 | 
				
			|||||||
 | 
					use ash::{
 | 
				
			||||||
 | 
					    khr::{surface, swapchain as khr_swapchain},
 | 
				
			||||||
 | 
					    vk,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::RenderCtx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod cube;
 | 
				
			||||||
 | 
					pub mod in_world;
 | 
				
			||||||
 | 
					mod init;
 | 
				
			||||||
 | 
					pub mod loading_world;
 | 
				
			||||||
 | 
					pub mod skybox;
 | 
				
			||||||
 | 
					mod swapchain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MAX_WIDTH: u32 = 3440;
 | 
				
			||||||
 | 
					const MAX_HEIGHT: u32 = 1440;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct SwapchainCtx {
 | 
				
			||||||
 | 
					    surface_loader: surface::Instance,
 | 
				
			||||||
 | 
					    swapchain_loader: khr_swapchain::Device,
 | 
				
			||||||
 | 
					    swap_images: Vec<vk::Image>,
 | 
				
			||||||
 | 
					    swap_views: Vec<vk::ImageView>,
 | 
				
			||||||
 | 
					    depth_mem: vk::DeviceMemory,
 | 
				
			||||||
 | 
					    depth_image: vk::Image,
 | 
				
			||||||
 | 
					    depth_view: vk::ImageView,
 | 
				
			||||||
 | 
					    framebufs: Vec<vk::Framebuffer>,
 | 
				
			||||||
 | 
					    swapchain: vk::SwapchainKHR,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum MemType {
 | 
				
			||||||
 | 
					    HostVisibile,
 | 
				
			||||||
 | 
					    HostInvisible,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RenderCtx {
 | 
				
			||||||
 | 
					    pub fn mem_alloc(&self, typ: MemType, size: u64) -> vk::DeviceMemory {
 | 
				
			||||||
 | 
					        let mem_info = vk::MemoryAllocateInfo::default()
 | 
				
			||||||
 | 
					            .allocation_size(size)
 | 
				
			||||||
 | 
					            .memory_type_index(match typ {
 | 
				
			||||||
 | 
					                MemType::HostVisibile => self.host_vis_idx,
 | 
				
			||||||
 | 
					                MemType::HostInvisible => self.host_invis_idx,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        let mem = unsafe { self.dev.allocate_memory(&mem_info, None) }
 | 
				
			||||||
 | 
					            .expect("Failed to allocate memory");
 | 
				
			||||||
 | 
					        println!("Allocated memory");
 | 
				
			||||||
 | 
					        mem
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn alloc_buf(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        mem: vk::DeviceMemory,
 | 
				
			||||||
 | 
					        size: vk::DeviceSize,
 | 
				
			||||||
 | 
					        usage: vk::BufferUsageFlags,
 | 
				
			||||||
 | 
					    ) -> vk::Buffer {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let buf_info = vk::BufferCreateInfo::default()
 | 
				
			||||||
 | 
					                .size(size)
 | 
				
			||||||
 | 
					                .usage(usage)
 | 
				
			||||||
 | 
					                .sharing_mode(vk::SharingMode::EXCLUSIVE);
 | 
				
			||||||
 | 
					            let buf = self
 | 
				
			||||||
 | 
					                .dev
 | 
				
			||||||
 | 
					                .create_buffer(&buf_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create buffer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .bind_buffer_memory(buf, mem, 0)
 | 
				
			||||||
 | 
					                .expect("Failed to bind buffer memory");
 | 
				
			||||||
 | 
					            println!("Created buffer");
 | 
				
			||||||
 | 
					            buf
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn buf_to_ptr(&self, mem: vk::DeviceMemory, buf: vk::Buffer) -> *mut std::ffi::c_void {
 | 
				
			||||||
 | 
					        let ptr = unsafe {
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .map_memory(mem, 0, vk::WHOLE_SIZE, vk::MemoryMapFlags::empty())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .expect("Failed to map memory");
 | 
				
			||||||
 | 
					        println!("Mapped memory");
 | 
				
			||||||
 | 
					        ptr
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn shader_mod_from_file(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        file: &str,
 | 
				
			||||||
 | 
					        flags: vk::ShaderModuleCreateFlags,
 | 
				
			||||||
 | 
					    ) -> vk::ShaderModule {
 | 
				
			||||||
 | 
					        let shader_bin = std::fs::read(file).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.dev.create_shader_module(
 | 
				
			||||||
 | 
					                &vk::ShaderModuleCreateInfo {
 | 
				
			||||||
 | 
					                    code_size: shader_bin.len(),
 | 
				
			||||||
 | 
					                    p_code: shader_bin.as_ptr() as *const u32,
 | 
				
			||||||
 | 
					                    flags,
 | 
				
			||||||
 | 
					                    ..Default::default()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .expect(&format!("Failed to create shader module form file {file}"))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn setup_simple_shader_stage(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        vert_shader: vk::ShaderModule,
 | 
				
			||||||
 | 
					        frag_shader: vk::ShaderModule,
 | 
				
			||||||
 | 
					    ) -> [vk::PipelineShaderStageCreateInfo; 2] {
 | 
				
			||||||
 | 
					        let vert_stage = vk::PipelineShaderStageCreateInfo::default()
 | 
				
			||||||
 | 
					            .stage(vk::ShaderStageFlags::VERTEX)
 | 
				
			||||||
 | 
					            .module(vert_shader)
 | 
				
			||||||
 | 
					            .name(c"main");
 | 
				
			||||||
 | 
					        let frag_stage = vk::PipelineShaderStageCreateInfo::default()
 | 
				
			||||||
 | 
					            .stage(vk::ShaderStageFlags::FRAGMENT)
 | 
				
			||||||
 | 
					            .module(frag_shader)
 | 
				
			||||||
 | 
					            .name(c"main");
 | 
				
			||||||
 | 
					        [vert_stage, frag_stage]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn make_sem(&self) -> vk::Semaphore {
 | 
				
			||||||
 | 
					        let sem_info = vk::SemaphoreCreateInfo::default();
 | 
				
			||||||
 | 
					        let sem = unsafe {
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .create_semaphore(&sem_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create semaphore")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        sem
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn make_fence(&self) -> vk::Fence {
 | 
				
			||||||
 | 
					        let fence_info = vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED);
 | 
				
			||||||
 | 
					        let fence = unsafe {
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .create_fence(&fence_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create fence")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        fence
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn wait_for_fence(&self, fence: vk::Fence) {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let fence = [fence];
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .wait_for_fences(&fence, true, u64::MAX)
 | 
				
			||||||
 | 
					                .expect("Failed to wait for fence");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn reset_fence(&self, fence: vk::Fence) {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let fence = [fence];
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .reset_fences(&fence)
 | 
				
			||||||
 | 
					                .expect("Failed to reset fence");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn start_cmd_buf(&self) {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .reset_command_buffer(self.cmd_buf, vk::CommandBufferResetFlags::empty())
 | 
				
			||||||
 | 
					                .expect("Failed to reset command buffer");
 | 
				
			||||||
 | 
					            let begin_info =
 | 
				
			||||||
 | 
					                vk::CommandBufferBeginInfo::default().flags(vk::CommandBufferUsageFlags::empty());
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .begin_command_buffer(self.cmd_buf, &begin_info)
 | 
				
			||||||
 | 
					                .expect("Failed to begin command buffer");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn end_cmd_buf(&self) {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .end_command_buffer(self.cmd_buf)
 | 
				
			||||||
 | 
					                .expect("Failed to end command buffer");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn submit_queue(&self, sem_avail: vk::Semaphore, sem_finish: vk::Semaphore, fence: vk::Fence) {
 | 
				
			||||||
 | 
					        let cmd_bufs = [self.cmd_buf];
 | 
				
			||||||
 | 
					        let wait_sems = [sem_avail];
 | 
				
			||||||
 | 
					        let signal_sems = [sem_finish];
 | 
				
			||||||
 | 
					        let submit_info = vk::SubmitInfo::default()
 | 
				
			||||||
 | 
					            .command_buffers(&cmd_bufs)
 | 
				
			||||||
 | 
					            .wait_semaphores(&wait_sems)
 | 
				
			||||||
 | 
					            .wait_dst_stage_mask(&[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT])
 | 
				
			||||||
 | 
					            .signal_semaphores(&signal_sems);
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.dev
 | 
				
			||||||
 | 
					                .queue_submit(self.queue, &[submit_info], fence)
 | 
				
			||||||
 | 
					                .expect("Failed to submit queue");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn queue_present(&self, swapchain: &SwapchainCtx, img_inx: u32, sem_finish: vk::Semaphore) {
 | 
				
			||||||
 | 
					        let swapchains = [swapchain.swapchain];
 | 
				
			||||||
 | 
					        let img_inxs = [img_inx];
 | 
				
			||||||
 | 
					        let wait_sems = [sem_finish];
 | 
				
			||||||
 | 
					        let present_info = vk::PresentInfoKHR::default()
 | 
				
			||||||
 | 
					            .swapchains(&swapchains)
 | 
				
			||||||
 | 
					            .image_indices(&img_inxs)
 | 
				
			||||||
 | 
					            .wait_semaphores(&wait_sems);
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            swapchain
 | 
				
			||||||
 | 
					                .swapchain_loader
 | 
				
			||||||
 | 
					                .queue_present(self.queue, &present_info)
 | 
				
			||||||
 | 
					                .expect("Failed to present queue");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,318 @@
 | 
				
			|||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ash::vk::{self};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{RenderCtx, decode_rif, game::Camera};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{MemType, loading_world::WorldComponent};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Skybox {
 | 
				
			||||||
 | 
					    pub buf: vk::Buffer,
 | 
				
			||||||
 | 
					    pub image: vk::Image,
 | 
				
			||||||
 | 
					    pub imageview: vk::ImageView,
 | 
				
			||||||
 | 
					    pub sampler: vk::Sampler,
 | 
				
			||||||
 | 
					    pipeline: vk::Pipeline,
 | 
				
			||||||
 | 
					    pipe_layout: vk::PipelineLayout,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WorldComponent for Skybox {
 | 
				
			||||||
 | 
					    fn descriptors(&self) -> HashMap<vk::DescriptorType, u32> {
 | 
				
			||||||
 | 
					        let mut map = HashMap::new();
 | 
				
			||||||
 | 
					        map.insert(vk::DescriptorType::COMBINED_IMAGE_SAMPLER, 1);
 | 
				
			||||||
 | 
					        map
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn desc_layout(&self, ctx: &RenderCtx) -> vk::DescriptorSetLayout {
 | 
				
			||||||
 | 
					        let image_binding = vk::DescriptorSetLayoutBinding::default()
 | 
				
			||||||
 | 
					            .binding(0)
 | 
				
			||||||
 | 
					            .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
 | 
				
			||||||
 | 
					            .descriptor_count(1)
 | 
				
			||||||
 | 
					            .stage_flags(vk::ShaderStageFlags::FRAGMENT);
 | 
				
			||||||
 | 
					        let layouts = [image_binding];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&layouts);
 | 
				
			||||||
 | 
					        let layout = unsafe {
 | 
				
			||||||
 | 
					            ctx.dev
 | 
				
			||||||
 | 
					                .create_descriptor_set_layout(&layout_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create descriptor set layout")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        layout
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_desc_set(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        ctx: &RenderCtx,
 | 
				
			||||||
 | 
					        desc_set: vk::DescriptorSet,
 | 
				
			||||||
 | 
					        _: (vk::ImageView, vk::Sampler),
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let img_info = vk::DescriptorImageInfo::default()
 | 
				
			||||||
 | 
					            .image_layout(vk::ImageLayout::GENERAL)
 | 
				
			||||||
 | 
					            .image_view(self.imageview)
 | 
				
			||||||
 | 
					            .sampler(self.sampler);
 | 
				
			||||||
 | 
					        let img_infos = &[img_info];
 | 
				
			||||||
 | 
					        let img_desc = vk::WriteDescriptorSet::default()
 | 
				
			||||||
 | 
					            .dst_set(desc_set)
 | 
				
			||||||
 | 
					            .dst_binding(0)
 | 
				
			||||||
 | 
					            .dst_array_element(0)
 | 
				
			||||||
 | 
					            .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
 | 
				
			||||||
 | 
					            .image_info(img_infos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            ctx.dev.update_descriptor_sets(&[img_desc], &[]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn pipeline(&self) -> (vk::Pipeline, vk::PipelineLayout) {
 | 
				
			||||||
 | 
					        (self.pipeline, self.pipe_layout)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn push_constants(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        camera: &Camera,
 | 
				
			||||||
 | 
					        res: [u32; 2],
 | 
				
			||||||
 | 
					        base_color: [f32; 4],
 | 
				
			||||||
 | 
					    ) -> Vec<(vk::ShaderStageFlags, u32, Vec<u8>)> {
 | 
				
			||||||
 | 
					        let mut constants = Vec::new();
 | 
				
			||||||
 | 
					        let cam_data: Vec<u8> = (Vec::<f32>::from([
 | 
				
			||||||
 | 
					            camera.origin.x,
 | 
				
			||||||
 | 
					            camera.origin.y,
 | 
				
			||||||
 | 
					            camera.origin.z,
 | 
				
			||||||
 | 
					            0.0,
 | 
				
			||||||
 | 
					            camera.rotation.x,
 | 
				
			||||||
 | 
					            camera.rotation.y,
 | 
				
			||||||
 | 
					            camera.rotation.z,
 | 
				
			||||||
 | 
					        ]))
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|f| f.to_ne_bytes())
 | 
				
			||||||
 | 
					        .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					        .into_flattened();
 | 
				
			||||||
 | 
					        constants.push((vk::ShaderStageFlags::VERTEX, 0, cam_data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let screen_res: Vec<u8> = res
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .map(|f| f.to_ne_bytes())
 | 
				
			||||||
 | 
					            .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					            .into_flattened();
 | 
				
			||||||
 | 
					        constants.push((vk::ShaderStageFlags::VERTEX, 32, screen_res));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        constants
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Skybox {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RenderCtx {
 | 
				
			||||||
 | 
					    pub(super) fn create_skybox(&self, pass: vk::RenderPass) -> Skybox {
 | 
				
			||||||
 | 
					        let skybox_mem = self.mem_alloc(MemType::HostVisibile, 3 * 2048 * 2048 * 6);
 | 
				
			||||||
 | 
					        let skybox_buf = self.alloc_buf(
 | 
				
			||||||
 | 
					            skybox_mem,
 | 
				
			||||||
 | 
					            3 * 2048 * 2048 * 6,
 | 
				
			||||||
 | 
					            vk::BufferUsageFlags::TRANSFER_SRC,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let skybox_ptr = self.buf_to_ptr(skybox_mem, skybox_buf);
 | 
				
			||||||
 | 
					        let img = std::fs::read("resources/skybox.rif").unwrap();
 | 
				
			||||||
 | 
					        let data = decode_rif(&img);
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            std::ptr::copy(data.as_ptr(), skybox_ptr as *mut u8, data.len());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let image = make_skybox_image(self);
 | 
				
			||||||
 | 
					        let imageview = make_skybox_image_view(self, image);
 | 
				
			||||||
 | 
					        let sampler = make_skybox_sampler(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pipe_layout = setup_pipe_layout(self);
 | 
				
			||||||
 | 
					        let pipeline = setup_pipeline(self, pass, pipe_layout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Skybox {
 | 
				
			||||||
 | 
					            buf: skybox_buf,
 | 
				
			||||||
 | 
					            image,
 | 
				
			||||||
 | 
					            imageview,
 | 
				
			||||||
 | 
					            sampler,
 | 
				
			||||||
 | 
					            pipeline,
 | 
				
			||||||
 | 
					            pipe_layout,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_skybox_image(ctx: &RenderCtx) -> vk::Image {
 | 
				
			||||||
 | 
					    let qf_idxs = [ctx.queue_idx];
 | 
				
			||||||
 | 
					    let create_info = vk::ImageCreateInfo::default()
 | 
				
			||||||
 | 
					        .flags(vk::ImageCreateFlags::CUBE_COMPATIBLE)
 | 
				
			||||||
 | 
					        .image_type(vk::ImageType::TYPE_2D)
 | 
				
			||||||
 | 
					        .format(vk::Format::R8G8B8_UNORM)
 | 
				
			||||||
 | 
					        .extent(vk::Extent3D::default().width(2048).height(2048).depth(1))
 | 
				
			||||||
 | 
					        .mip_levels(1)
 | 
				
			||||||
 | 
					        .array_layers(6)
 | 
				
			||||||
 | 
					        .samples(vk::SampleCountFlags::TYPE_1)
 | 
				
			||||||
 | 
					        .tiling(vk::ImageTiling::OPTIMAL)
 | 
				
			||||||
 | 
					        .usage(vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED)
 | 
				
			||||||
 | 
					        .sharing_mode(vk::SharingMode::EXCLUSIVE)
 | 
				
			||||||
 | 
					        .initial_layout(vk::ImageLayout::UNDEFINED)
 | 
				
			||||||
 | 
					        .queue_family_indices(&qf_idxs);
 | 
				
			||||||
 | 
					    let image =
 | 
				
			||||||
 | 
					        unsafe { ctx.dev.create_image(&create_info, None) }.expect("Failed to create image");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let skybox_mem_size: vk::MemoryRequirements =
 | 
				
			||||||
 | 
					        unsafe { ctx.dev.get_image_memory_requirements(image) };
 | 
				
			||||||
 | 
					    let skybox_dev_mem = ctx.mem_alloc(MemType::HostInvisible, skybox_mem_size.size);
 | 
				
			||||||
 | 
					    unsafe { ctx.dev.bind_image_memory(image, skybox_dev_mem, 0) }
 | 
				
			||||||
 | 
					        .expect("Failed to bind image memory");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    image
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_skybox_image_view(ctx: &RenderCtx, image: vk::Image) -> vk::ImageView {
 | 
				
			||||||
 | 
					    let create_info = vk::ImageViewCreateInfo::default()
 | 
				
			||||||
 | 
					        .image(image)
 | 
				
			||||||
 | 
					        .view_type(vk::ImageViewType::CUBE)
 | 
				
			||||||
 | 
					        .format(vk::Format::R8G8B8_UNORM)
 | 
				
			||||||
 | 
					        .components(vk::ComponentMapping::default())
 | 
				
			||||||
 | 
					        .subresource_range(
 | 
				
			||||||
 | 
					            vk::ImageSubresourceRange::default()
 | 
				
			||||||
 | 
					                .aspect_mask(vk::ImageAspectFlags::COLOR)
 | 
				
			||||||
 | 
					                .base_mip_level(0)
 | 
				
			||||||
 | 
					                .level_count(1)
 | 
				
			||||||
 | 
					                .base_array_layer(0)
 | 
				
			||||||
 | 
					                .layer_count(6),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    unsafe { ctx.dev.create_image_view(&create_info, None) }.expect("Failed to create image view")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_skybox_sampler(ctx: &RenderCtx) -> vk::Sampler {
 | 
				
			||||||
 | 
					    let create_info = vk::SamplerCreateInfo::default()
 | 
				
			||||||
 | 
					        .mag_filter(vk::Filter::LINEAR)
 | 
				
			||||||
 | 
					        .min_filter(vk::Filter::LINEAR)
 | 
				
			||||||
 | 
					        .mipmap_mode(vk::SamplerMipmapMode::LINEAR)
 | 
				
			||||||
 | 
					        .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_EDGE)
 | 
				
			||||||
 | 
					        .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE)
 | 
				
			||||||
 | 
					        .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE)
 | 
				
			||||||
 | 
					        .max_anisotropy(1.0)
 | 
				
			||||||
 | 
					        .max_lod(1.0)
 | 
				
			||||||
 | 
					        .border_color(vk::BorderColor::FLOAT_OPAQUE_WHITE);
 | 
				
			||||||
 | 
					    unsafe { ctx.dev.create_sampler(&create_info, None) }.expect("Failed to create sampler")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_skybox_shaders(ctx: &RenderCtx) -> (vk::ShaderModule, vk::ShaderModule) {
 | 
				
			||||||
 | 
					    let skybox_vert_shader = ctx.shader_mod_from_file(
 | 
				
			||||||
 | 
					        "shaders/skybox_vert.spv",
 | 
				
			||||||
 | 
					        vk::ShaderModuleCreateFlags::empty(),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    let skybox_frag_shader = ctx.shader_mod_from_file(
 | 
				
			||||||
 | 
					        "shaders/skybox_rag.spv",
 | 
				
			||||||
 | 
					        vk::ShaderModuleCreateFlags::empty(),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (skybox_vert_shader, skybox_frag_shader)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_desc_layout(ctx: &RenderCtx) -> vk::DescriptorSetLayout {
 | 
				
			||||||
 | 
					    let image_binding = vk::DescriptorSetLayoutBinding::default()
 | 
				
			||||||
 | 
					        .binding(0)
 | 
				
			||||||
 | 
					        .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
 | 
				
			||||||
 | 
					        .descriptor_count(1)
 | 
				
			||||||
 | 
					        .stage_flags(vk::ShaderStageFlags::FRAGMENT);
 | 
				
			||||||
 | 
					    let layouts = [image_binding];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&layouts);
 | 
				
			||||||
 | 
					    let layout = unsafe { ctx.dev.create_descriptor_set_layout(&layout_info, None) }
 | 
				
			||||||
 | 
					        .expect("Failed to create descriptor set layout");
 | 
				
			||||||
 | 
					    layout
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_pipe_layout(ctx: &RenderCtx) -> vk::PipelineLayout {
 | 
				
			||||||
 | 
					    let layout = setup_desc_layout(ctx);
 | 
				
			||||||
 | 
					    let push_range: [vk::PushConstantRange; 1] = [
 | 
				
			||||||
 | 
					        vk::PushConstantRange::default()
 | 
				
			||||||
 | 
					            .stage_flags(vk::ShaderStageFlags::VERTEX)
 | 
				
			||||||
 | 
					            .offset(0)
 | 
				
			||||||
 | 
					            .size(48), // vec4 camera_orig, camera_rot; uvec2 screen_res
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let layouts = &[layout];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pipe_layout = vk::PipelineLayoutCreateInfo::default()
 | 
				
			||||||
 | 
					        .set_layouts(layouts.as_ref())
 | 
				
			||||||
 | 
					        .push_constant_ranges(&push_range);
 | 
				
			||||||
 | 
					    let pipe_layout = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_pipeline_layout(&pipe_layout, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create pipeline layout")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    pipe_layout
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup_pipeline(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    pass: vk::RenderPass,
 | 
				
			||||||
 | 
					    layout: vk::PipelineLayout,
 | 
				
			||||||
 | 
					) -> vk::Pipeline {
 | 
				
			||||||
 | 
					    let (vert_shader, frag_shader) = load_skybox_shaders(ctx);
 | 
				
			||||||
 | 
					    let shader_stages = ctx.setup_simple_shader_stage(vert_shader, frag_shader);
 | 
				
			||||||
 | 
					    let vert_input = vk::PipelineVertexInputStateCreateInfo::default();
 | 
				
			||||||
 | 
					    let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .topology(vk::PrimitiveTopology::TRIANGLE_LIST);
 | 
				
			||||||
 | 
					    let rasterization = vk::PipelineRasterizationStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .polygon_mode(vk::PolygonMode::FILL)
 | 
				
			||||||
 | 
					        .cull_mode(vk::CullModeFlags::NONE)
 | 
				
			||||||
 | 
					        .front_face(vk::FrontFace::CLOCKWISE)
 | 
				
			||||||
 | 
					        .line_width(1.0);
 | 
				
			||||||
 | 
					    let multisample = vk::PipelineMultisampleStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .rasterization_samples(vk::SampleCountFlags::TYPE_1);
 | 
				
			||||||
 | 
					    let depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .depth_test_enable(true)
 | 
				
			||||||
 | 
					        .depth_write_enable(true)
 | 
				
			||||||
 | 
					        .depth_compare_op(vk::CompareOp::LESS)
 | 
				
			||||||
 | 
					        .depth_bounds_test_enable(true)
 | 
				
			||||||
 | 
					        .stencil_test_enable(false)
 | 
				
			||||||
 | 
					        .min_depth_bounds(0.0)
 | 
				
			||||||
 | 
					        .max_depth_bounds(1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let blend = vk::PipelineColorBlendAttachmentState::default()
 | 
				
			||||||
 | 
					        .src_color_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .dst_color_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .color_blend_op(vk::BlendOp::ADD)
 | 
				
			||||||
 | 
					        .src_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .dst_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
 | 
				
			||||||
 | 
					        .alpha_blend_op(vk::BlendOp::ADD)
 | 
				
			||||||
 | 
					        .color_write_mask(
 | 
				
			||||||
 | 
					            vk::ColorComponentFlags::R
 | 
				
			||||||
 | 
					                | vk::ColorComponentFlags::G
 | 
				
			||||||
 | 
					                | vk::ColorComponentFlags::B
 | 
				
			||||||
 | 
					                | vk::ColorComponentFlags::A,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let blend_attachments = [blend];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let color_blend = vk::PipelineColorBlendStateCreateInfo::default()
 | 
				
			||||||
 | 
					        .attachments(blend_attachments.as_ref())
 | 
				
			||||||
 | 
					        .logic_op_enable(false)
 | 
				
			||||||
 | 
					        .logic_op(vk::LogicOp::COPY)
 | 
				
			||||||
 | 
					        .blend_constants([1.0, 1.0, 1.0, 1.0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let dynamic = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&[
 | 
				
			||||||
 | 
					        vk::DynamicState::VIEWPORT_WITH_COUNT,
 | 
				
			||||||
 | 
					        vk::DynamicState::SCISSOR_WITH_COUNT,
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pipe_info = vk::GraphicsPipelineCreateInfo::default()
 | 
				
			||||||
 | 
					        .stages(&shader_stages)
 | 
				
			||||||
 | 
					        .vertex_input_state(&vert_input)
 | 
				
			||||||
 | 
					        .input_assembly_state(&input_assembly)
 | 
				
			||||||
 | 
					        .rasterization_state(&rasterization)
 | 
				
			||||||
 | 
					        .multisample_state(&multisample)
 | 
				
			||||||
 | 
					        .depth_stencil_state(&depth_stencil)
 | 
				
			||||||
 | 
					        .color_blend_state(&color_blend)
 | 
				
			||||||
 | 
					        .layout(layout)
 | 
				
			||||||
 | 
					        .dynamic_state(&dynamic)
 | 
				
			||||||
 | 
					        .render_pass(pass)
 | 
				
			||||||
 | 
					        .subpass(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pipe = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_graphics_pipelines(vk::PipelineCache::null(), &[pipe_info], None)
 | 
				
			||||||
 | 
					            .expect("Failed to create graphics pipeline")
 | 
				
			||||||
 | 
					            .remove(0)
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    println!("Created pipeline");
 | 
				
			||||||
 | 
					    pipe
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					use std::cmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ash::{
 | 
				
			||||||
 | 
					    khr::{surface, swapchain as khr_swapchain},
 | 
				
			||||||
 | 
					    vk,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    RenderCtx,
 | 
				
			||||||
 | 
					    render::{MAX_HEIGHT, MAX_WIDTH},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn setup_swapchain(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    surface_loader: &surface::Instance,
 | 
				
			||||||
 | 
					    swapchain_loader: &khr_swapchain::Device,
 | 
				
			||||||
 | 
					    width: u32,
 | 
				
			||||||
 | 
					    height: u32,
 | 
				
			||||||
 | 
					) -> (vk::SwapchainKHR, vk::Extent2D) {
 | 
				
			||||||
 | 
					    let caps = unsafe {
 | 
				
			||||||
 | 
					        surface_loader
 | 
				
			||||||
 | 
					            .get_physical_device_surface_capabilities(ctx.pdev, ctx.surface)
 | 
				
			||||||
 | 
					            .expect("Failed to get surface capabilities")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let formats = unsafe {
 | 
				
			||||||
 | 
					        surface_loader
 | 
				
			||||||
 | 
					            .get_physical_device_surface_formats(ctx.pdev, ctx.surface)
 | 
				
			||||||
 | 
					            .expect("Failed to get surface formats")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let format = (formats)
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .filter(|f| {
 | 
				
			||||||
 | 
					            f.format == vk::Format::B8G8R8A8_UNORM
 | 
				
			||||||
 | 
					                && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .next()
 | 
				
			||||||
 | 
					        .expect("No suitable format found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // When the window is resized fast, then the caps goes out of sync of the target extents
 | 
				
			||||||
 | 
					    // Thus we are using the passed-in (target) extents instead of the cap extents.
 | 
				
			||||||
 | 
					    // assert_eq!(caps.current_extent.width, width);
 | 
				
			||||||
 | 
					    // assert_eq!(caps.current_extent.height, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let swap_create = vk::SwapchainCreateInfoKHR::default()
 | 
				
			||||||
 | 
					        .surface(ctx.surface)
 | 
				
			||||||
 | 
					        .min_image_count(caps.min_image_count)
 | 
				
			||||||
 | 
					        .image_format(format.format)
 | 
				
			||||||
 | 
					        .image_color_space(format.color_space)
 | 
				
			||||||
 | 
					        .image_extent(vk::Extent2D {
 | 
				
			||||||
 | 
					            width: cmp::min(cmp::max(caps.current_extent.width, width), MAX_WIDTH),
 | 
				
			||||||
 | 
					            height: cmp::min(cmp::max(caps.current_extent.height, height), MAX_HEIGHT),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .image_array_layers(1)
 | 
				
			||||||
 | 
					        .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
 | 
				
			||||||
 | 
					        .image_sharing_mode(vk::SharingMode::EXCLUSIVE)
 | 
				
			||||||
 | 
					        .pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY)
 | 
				
			||||||
 | 
					        .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
 | 
				
			||||||
 | 
					        .present_mode(vk::PresentModeKHR::MAILBOX)
 | 
				
			||||||
 | 
					        .clipped(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let swapchain = unsafe {
 | 
				
			||||||
 | 
					        swapchain_loader
 | 
				
			||||||
 | 
					            .create_swapchain(&swap_create, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create swapchain")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    println!("Created swapchain");
 | 
				
			||||||
 | 
					    (swapchain, caps.current_extent)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn make_swap_images(
 | 
				
			||||||
 | 
					    swapchain: vk::SwapchainKHR,
 | 
				
			||||||
 | 
					    swapchain_loader: &khr_swapchain::Device,
 | 
				
			||||||
 | 
					) -> Vec<vk::Image> {
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        let images = swapchain_loader
 | 
				
			||||||
 | 
					            .get_swapchain_images(swapchain)
 | 
				
			||||||
 | 
					            .expect("Failed to get swapchain images");
 | 
				
			||||||
 | 
					        println!("Fetched swapchain images");
 | 
				
			||||||
 | 
					        images
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn make_swap_views(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    swap_images: &[vk::Image],
 | 
				
			||||||
 | 
					    format: vk::Format,
 | 
				
			||||||
 | 
					) -> Vec<vk::ImageView> {
 | 
				
			||||||
 | 
					    let mut views = Vec::new();
 | 
				
			||||||
 | 
					    for img in swap_images.iter() {
 | 
				
			||||||
 | 
					        let view_info = vk::ImageViewCreateInfo::default()
 | 
				
			||||||
 | 
					            .image(*img)
 | 
				
			||||||
 | 
					            .view_type(vk::ImageViewType::TYPE_2D)
 | 
				
			||||||
 | 
					            .format(format)
 | 
				
			||||||
 | 
					            .components(vk::ComponentMapping::default())
 | 
				
			||||||
 | 
					            .subresource_range(
 | 
				
			||||||
 | 
					                vk::ImageSubresourceRange::default()
 | 
				
			||||||
 | 
					                    .aspect_mask(vk::ImageAspectFlags::COLOR)
 | 
				
			||||||
 | 
					                    .base_mip_level(0)
 | 
				
			||||||
 | 
					                    .level_count(1)
 | 
				
			||||||
 | 
					                    .base_array_layer(0)
 | 
				
			||||||
 | 
					                    .layer_count(1),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        let view = unsafe {
 | 
				
			||||||
 | 
					            ctx.dev
 | 
				
			||||||
 | 
					                .create_image_view(&view_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create image view")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        views.push(view);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    views
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn make_depth_img(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    width: u32,
 | 
				
			||||||
 | 
					    height: u32,
 | 
				
			||||||
 | 
					    mem: vk::DeviceMemory,
 | 
				
			||||||
 | 
					) -> vk::Image {
 | 
				
			||||||
 | 
					    let queue_fams = [ctx.queue_idx];
 | 
				
			||||||
 | 
					    let img_info = vk::ImageCreateInfo::default()
 | 
				
			||||||
 | 
					        .flags(vk::ImageCreateFlags::empty())
 | 
				
			||||||
 | 
					        .image_type(vk::ImageType::TYPE_2D)
 | 
				
			||||||
 | 
					        .format(vk::Format::D32_SFLOAT)
 | 
				
			||||||
 | 
					        .extent(vk::Extent3D {
 | 
				
			||||||
 | 
					            width,
 | 
				
			||||||
 | 
					            height,
 | 
				
			||||||
 | 
					            depth: 1,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .mip_levels(1)
 | 
				
			||||||
 | 
					        .array_layers(1)
 | 
				
			||||||
 | 
					        .samples(vk::SampleCountFlags::TYPE_1)
 | 
				
			||||||
 | 
					        .tiling(vk::ImageTiling::OPTIMAL)
 | 
				
			||||||
 | 
					        .usage(vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT)
 | 
				
			||||||
 | 
					        .sharing_mode(vk::SharingMode::EXCLUSIVE)
 | 
				
			||||||
 | 
					        .queue_family_indices(&queue_fams)
 | 
				
			||||||
 | 
					        .initial_layout(vk::ImageLayout::UNDEFINED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let img = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_image(&img_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create image")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    println!("Created image");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .bind_image_memory(img, mem, 0)
 | 
				
			||||||
 | 
					            .expect("Failed to bind image memory")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    img
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn make_depth_view(ctx: &RenderCtx, depth_img: vk::Image, format: vk::Format) -> vk::ImageView {
 | 
				
			||||||
 | 
					    let view_info = vk::ImageViewCreateInfo::default()
 | 
				
			||||||
 | 
					        .image(depth_img)
 | 
				
			||||||
 | 
					        .view_type(vk::ImageViewType::TYPE_2D)
 | 
				
			||||||
 | 
					        .format(format)
 | 
				
			||||||
 | 
					        .components(vk::ComponentMapping::default())
 | 
				
			||||||
 | 
					        .subresource_range(
 | 
				
			||||||
 | 
					            vk::ImageSubresourceRange::default()
 | 
				
			||||||
 | 
					                .aspect_mask(vk::ImageAspectFlags::DEPTH)
 | 
				
			||||||
 | 
					                .base_mip_level(0)
 | 
				
			||||||
 | 
					                .level_count(1)
 | 
				
			||||||
 | 
					                .base_array_layer(0)
 | 
				
			||||||
 | 
					                .layer_count(1),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    let view = unsafe {
 | 
				
			||||||
 | 
					        ctx.dev
 | 
				
			||||||
 | 
					            .create_image_view(&view_info, None)
 | 
				
			||||||
 | 
					            .expect("Failed to create image view")
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    view
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn make_framebufs(
 | 
				
			||||||
 | 
					    ctx: &RenderCtx,
 | 
				
			||||||
 | 
					    swap_views: &Vec<vk::ImageView>,
 | 
				
			||||||
 | 
					    depth_view: &vk::ImageView,
 | 
				
			||||||
 | 
					    pass: &vk::RenderPass,
 | 
				
			||||||
 | 
					    width: u32,
 | 
				
			||||||
 | 
					    height: u32,
 | 
				
			||||||
 | 
					) -> Vec<vk::Framebuffer> {
 | 
				
			||||||
 | 
					    let mut framebufs = Vec::new();
 | 
				
			||||||
 | 
					    for view in swap_views.iter() {
 | 
				
			||||||
 | 
					        let attachments = [*view, *depth_view];
 | 
				
			||||||
 | 
					        let framebuf_info = vk::FramebufferCreateInfo::default()
 | 
				
			||||||
 | 
					            .render_pass(*pass)
 | 
				
			||||||
 | 
					            .attachments(attachments.as_ref())
 | 
				
			||||||
 | 
					            .width(width)
 | 
				
			||||||
 | 
					            .height(height)
 | 
				
			||||||
 | 
					            .layers(1);
 | 
				
			||||||
 | 
					        let framebuf = unsafe {
 | 
				
			||||||
 | 
					            ctx.dev
 | 
				
			||||||
 | 
					                .create_framebuffer(&framebuf_info, None)
 | 
				
			||||||
 | 
					                .expect("Failed to create framebuffer")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        framebufs.push(framebuf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    framebufs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue