#![allow(unused_variables, unused_mut)] use ash::Device; use ash::Entry; use ash::Instance; use ash::khr::{surface, swapchain}; use ash::vk; use ash::vk::ImageCreateFlags; use sdl2::mouse::MouseUtil; use std::cmp; use std::ffi::CStr; use std::ffi::CString; use std::thread; use std::time::Duration; use std::time::Instant; use raw_window_handle::HasDisplayHandle; use raw_window_handle::HasWindowHandle; use sdl2::event::Event; use sdl2::event::WindowEvent; use sdl2::keyboard::Keycode; use sdl2::video::Window; const APP_NAME: &str = "MineClone"; const MOV_STEP: f32 = 0.05; const ROT_MOUSE_SCALE: f32 = 0.001; const MAX_WIDTH: u32 = 3440; const MAX_HEIGHT: u32 = 1440; const MESH_SIZE: u64 = 36 * 2 * 4 * 4; #[rustfmt::skip] const POSITIONS: [f32; 36 * 2 * 4] = [ // BOTTOM -0.5, 0.5, -0.5, 1.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 1.0, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, -0.5, 1.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 1.0, 0.0, 0.0, -0.5, 0.5, -0.5, 1.0, 0.0, 1.0, 0.0, 0.0, // TOP 0.5, -0.5, 0.5, 1.0, 0.0, -1.0, 0.0, 0.0, -0.5, -0.5, -0.5, 1.0, 0.0, -1.0, 0.0, 0.0, -0.5, -0.5, 0.5, 1.0, 0.0, -1.0, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, -1.0, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, -1.0, 0.0, 0.0, -0.5, -0.5, -0.5, 1.0, 0.0, -1.0, 0.0, 0.0, // FRONT -0.5, -0.5, -0.5, 1.0, 0.0, 0.0, -1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 0.0, 0.0, -1.0, 0.0, -0.5, 0.5, -0.5, 1.0, 0.0, 0.0, -1.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, -1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 0.0, 0.0, -1.0, 0.0, -0.5, -0.5, -0.5, 1.0, 0.0, 0.0, -1.0, 0.0, // BACK 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, // LEFT -0.5, -0.5, -0.5, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, -0.5, 0.5, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, 0.5, -0.5, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, -1.0, 0.0, 0.0, 0.0, -0.5, -0.5, -0.5, 1.0, -1.0, 0.0, 0.0, 0.0, // RIGHT 0.5, 0.5, 0.5, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 1.0, 0.0, 0.0, 0.0, ]; fn create_instance(window: &Window, entry: &Entry) -> Instance { unsafe { 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::>(); let exts: &[*const i8] = exts.as_slice(); let insinfo = vk::InstanceCreateInfo::default() .application_info(&appinfo) .enabled_extension_names(exts); let instance = entry .create_instance(&insinfo, None) .expect("Failed to create instance"); println!("Created instance"); instance } } fn find_pdev_dgpu(instance: &Instance) -> vk::PhysicalDevice { unsafe { let mut pdevs = instance .enumerate_physical_devices() .expect("Failed to enumerate devices"); for (i, d) in pdevs.iter().enumerate() { let props = 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: {}", 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); } } fn make_surface(entry: &Entry, instance: &Instance, window: &Window) -> vk::SurfaceKHR { unsafe { let surface = 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 } } // Using Intel GPU hardware terminology 🥴 fn find_rcs_queue_inx(instance: &Instance, pdev: &vk::PhysicalDevice) -> Option { unsafe { let qfams = 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::>(); 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 { unsafe { let mem_props = 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 { unsafe { let mem_props = 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; } } fn mem_alloc(dev: &Device, mem_type_inx: u32, size: u64) -> vk::DeviceMemory { unsafe { let mem_info = vk::MemoryAllocateInfo::default() .allocation_size(size) .memory_type_index(mem_type_inx); let mem = dev .allocate_memory(&mem_info, None) .expect("Failed to allocate memory"); println!("Allocated memory"); mem } } fn make_depth_img( dev: &Device, host_invisible_inx: u32, width: u32, height: u32, mem: vk::DeviceMemory, qfam: u32, ) -> vk::Image { unsafe { let queue_fams = [qfam]; 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 = dev .create_image(&img_info, None) .expect("Failed to create image"); println!("Created image"); dev.bind_image_memory(img, mem, 0) .expect("Failed to bind image memory"); img } } fn alloc_buf( dev: &Device, mem: &vk::DeviceMemory, size: u64, usage: vk::BufferUsageFlags, ) -> vk::Buffer { unsafe { let buf_info = vk::BufferCreateInfo::default() .size(size) .usage(usage) .sharing_mode(vk::SharingMode::EXCLUSIVE); let buf = dev .create_buffer(&buf_info, None) .expect("Failed to create buffer"); dev.bind_buffer_memory(buf, *mem, 0) .expect("Failed to bind buffer memory"); println!("Created buffer"); buf } } fn buf_to_ptr(dev: &Device, mem: &vk::DeviceMemory, buf: &vk::Buffer) -> *mut std::ffi::c_void { unsafe { let ptr = dev .map_memory(*mem, 0, vk::WHOLE_SIZE, vk::MemoryMapFlags::empty()) .expect("Failed to map memory"); println!("Mapped memory"); ptr } } fn setup_desc_layout(dev: &Device) -> 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 { dev.create_descriptor_set_layout(&layout_info, None) .expect("Failed to create descriptor set layout") }; layout } fn setup_render_pass(dev: &Device) -> 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 { dev.create_render_pass(&pass_info, None) .expect("Failed to create render pass") }; pass } fn setup_pipe_layout(dev: &Device) -> vk::PipelineLayout { let layout = setup_desc_layout(&dev); let push_range: [vk::PushConstantRange; 2] = [ vk::PushConstantRange::default() .stage_flags(vk::ShaderStageFlags::VERTEX) .offset(0) .size(48), // vec4 camera_orig, camera_rot 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 { dev.create_pipeline_layout(&pipe_layout, None) .expect("Failed to create pipeline layout") }; pipe_layout } fn setup_shader_stage( dev: &Device, 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 setup_pipeline( dev: &Device, vert_shader: &vk::ShaderModule, frag_shader: &vk::ShaderModule, pass: &vk::RenderPass, pipe_layout: &vk::PipelineLayout, ) -> vk::Pipeline { let shader_stages = setup_shader_stage(&dev, *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(*pipe_layout) .dynamic_state(&dynamic) .render_pass(*pass) .subpass(0); let pipe = unsafe { dev.create_graphics_pipelines(vk::PipelineCache::null(), &[pipe_info], None) .expect("Failed to create graphics pipeline") .remove(0) }; println!("Created pipeline"); pipe } // TODO dynamic state for resizing fn setup_swapchain( pdev: &vk::PhysicalDevice, dev: &Device, surface: &vk::SurfaceKHR, surface_loader: &surface::Instance, swapchain_loader: &ash::khr::swapchain::Device, instance: &Instance, width: u32, height: u32, ) -> (vk::SwapchainKHR, vk::Extent2D) { let caps = unsafe { surface_loader .get_physical_device_surface_capabilities(*pdev, *surface) .expect("Failed to get surface capabilities") }; let formats = unsafe { surface_loader .get_physical_device_surface_formats(*pdev, *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(*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) } fn setup_desc_pool(dev: &Device) -> vk::DescriptorPool { let pool_size_storage = vk::DescriptorPoolSize::default() .ty(vk::DescriptorType::STORAGE_BUFFER) .descriptor_count(1); let pool_size_image = vk::DescriptorPoolSize::default() .ty(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) .descriptor_count(1); let pool_sizes = [pool_size_storage, pool_size_image]; let pool_info = vk::DescriptorPoolCreateInfo::default() .max_sets(1) .pool_sizes(&pool_sizes); let pool = unsafe { dev.create_descriptor_pool(&pool_info, None) .expect("Failed to create descriptor pool") }; pool } fn make_swap_images( dev: &Device, swapchain: &vk::SwapchainKHR, swapchain_loader: &swapchain::Device, ) -> Vec { unsafe { let images = swapchain_loader .get_swapchain_images(*swapchain) .expect("Failed to get swapchain images"); println!("Fetched swapchain images"); images } } fn make_swap_views( dev: &Device, swap_images: &Vec, format: vk::Format, ) -> Vec { 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 { dev.create_image_view(&view_info, None) .expect("Failed to create image view") }; views.push(view); } views } fn make_depth_view(dev: &Device, 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 { dev.create_image_view(&view_info, None) .expect("Failed to create image view") }; view } fn make_framebufs( dev: &Device, swap_views: &Vec, depth_view: &vk::ImageView, pass: &vk::RenderPass, width: u32, height: u32, ) -> Vec { 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 { dev.create_framebuffer(&framebuf_info, None) .expect("Failed to create framebuffer") }; framebufs.push(framebuf); } framebufs } fn make_desc_sets(dev: &Device, desc_pool: &vk::DescriptorPool) -> Vec { let layout = setup_desc_layout(&dev); let layouts = [layout]; let alloc_info = vk::DescriptorSetAllocateInfo::default() .descriptor_pool(*desc_pool) .set_layouts(&layouts); let sets = unsafe { dev.allocate_descriptor_sets(&alloc_info) .expect("Failed to allocate descriptor sets") }; sets } fn write_desc_sets( dev: &Device, desc_sets: &Vec, mesh_buf: &vk::Buffer, image_view: vk::ImageView, ) { let buf_info = vk::DescriptorBufferInfo::default() .buffer(*mesh_buf) .offset(0) .range(vk::WHOLE_SIZE); let buf_infos = [buf_info]; let buf_desc = vk::WriteDescriptorSet::default() .dst_set(desc_sets[0]) .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::UNDEFINED) .image_view(image_view); let img_infos = &[img_info]; let img_desc = vk::WriteDescriptorSet::default() .dst_set(desc_sets[0]) .dst_binding(1) .dst_array_element(0) .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) .image_info(img_infos); unsafe { dev.update_descriptor_sets(&[buf_desc, img_desc], &[]); } } fn make_sem(dev: &Device) -> vk::Semaphore { let sem_info = vk::SemaphoreCreateInfo::default(); let sem = unsafe { dev.create_semaphore(&sem_info, None) .expect("Failed to create semaphore") }; sem } fn make_fence(dev: &Device) -> vk::Fence { let fence_info = vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED); let fence = unsafe { dev.create_fence(&fence_info, None) .expect("Failed to create fence") }; fence } fn wait_for_fence(dev: &Device, fence: &vk::Fence) { unsafe { let fence = [*fence]; dev.wait_for_fences(&fence, true, u64::MAX) .expect("Failed to wait for fence"); } } fn reset_fence(dev: &Device, fence: &vk::Fence) { unsafe { let fence = [*fence]; dev.reset_fences(&fence).expect("Failed to reset fence"); } } fn ack_next_img( dev: &Device, swapchain_loader: &swapchain::Device, swapchain: &vk::SwapchainKHR, sem_avail: &vk::Semaphore, fence: &vk::Fence, ) -> u32 { unsafe { let (img_inx, _) = swapchain_loader .acquire_next_image(*swapchain, u64::MAX, *sem_avail, vk::Fence::null()) .expect("Failed to acquire next image"); img_inx } } fn record_commands( dev: &Device, cmd_buf: &vk::CommandBuffer, framebuf: &vk::Framebuffer, pass: &vk::RenderPass, layout: &vk::PipelineLayout, width: u32, height: u32, pipe: &vk::Pipeline, desc_sets: &Vec, camera: &Camera, skybox_buffer: &vk::Buffer, skybox_image: &vk::Image, ) { 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(*framebuf) .render_area( vk::Rect2D::default() .offset(vk::Offset2D::default()) .extent(vk::Extent2D { width, height }), ) .clear_values(&clear_vals); unsafe { dev.cmd_begin_render_pass(*cmd_buf, &render_pass_info, vk::SubpassContents::INLINE); dev.cmd_bind_pipeline(*cmd_buf, vk::PipelineBindPoint::GRAPHICS, *pipe); 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, height })], ); let cam_data: Vec = (Vec::::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::>() .into_flattened(); let screen_res: Vec = (Vec::::from([width, height])) .iter() .map(|f| f.to_ne_bytes()) .collect::>() .into_flattened(); let base_color: Vec = (Vec::::from([0.0, 1.0, 1.0, 1.0])) .iter() .map(|f| f.to_ne_bytes()) .collect::>() .into_flattened(); dev.cmd_push_constants( *cmd_buf, *layout, vk::ShaderStageFlags::VERTEX, 0, cam_data.as_ref(), ); dev.cmd_push_constants( *cmd_buf, *layout, vk::ShaderStageFlags::VERTEX, 32, screen_res.as_ref(), ); dev.cmd_push_constants( *cmd_buf, *layout, vk::ShaderStageFlags::FRAGMENT, 48, base_color.as_ref(), ); 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::>(); dev.cmd_copy_buffer_to_image( *cmd_buf, *skybox_buffer, *skybox_image, vk::ImageLayout::GENERAL, ®ions, ); dev.cmd_draw(*cmd_buf, 36, 1, 0, 0); dev.cmd_end_render_pass(*cmd_buf); } } fn start_cmd_buf(dev: &Device, cmd_buf: &vk::CommandBuffer) { unsafe { dev.reset_command_buffer(*cmd_buf, vk::CommandBufferResetFlags::empty()) .expect("Failed to reset command buffer"); let begin_info = vk::CommandBufferBeginInfo::default().flags(vk::CommandBufferUsageFlags::empty()); dev.begin_command_buffer(*cmd_buf, &begin_info) .expect("Failed to begin command buffer"); } } fn end_cmd_buf(dev: &Device, cmd_buf: &vk::CommandBuffer) { unsafe { dev.end_command_buffer(*cmd_buf) .expect("Failed to end command buffer"); } } fn submit_queue( dev: &Device, queue: &vk::Queue, cmd_buf: &vk::CommandBuffer, sem_avail: &vk::Semaphore, sem_finish: &vk::Semaphore, fence: &vk::Fence, ) { let cmd_bufs = [*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 { dev.queue_submit(*queue, &[submit_info], *fence) .expect("Failed to submit queue"); } } fn queue_present( swapchain_loader: &swapchain::Device, queue: &vk::Queue, swapchain: &vk::SwapchainKHR, img_inx: u32, sem_finish: &vk::Semaphore, ) { let swapchains = [*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_loader .queue_present(*queue, &present_info) .expect("Failed to present queue"); } } #[derive(Debug)] struct Vector3 { x: f32, y: f32, z: f32, } #[derive(Debug)] struct Camera { origin: Vector3, rotation: Vector3, } fn handle_cont_key(keycode: Keycode, camera: &mut Camera, mouse: &MouseUtil) { 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 decode_rif(raw: &[u8]) -> &[u8] { &raw[18..] } fn main() { let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); let mouse = sdl_context.mouse(); let mut width = 1024; let mut height = 768; let mut window = video_subsystem .window(APP_NAME, width, height) .vulkan() .resizable() .build() .unwrap(); // We start in relative move mouse.set_relative_mouse_mode(true); let entry = Entry::linked(); let instance = create_instance(&window, &entry); let surface = make_surface(&entry, &instance, &window); let pdev = find_pdev_dgpu(&instance); let rcs_queue_inx = find_rcs_queue_inx(&instance, &pdev).expect("No RCS queue found"); let dev = make_dev( &instance, &pdev, rcs_queue_inx, vec![c"VK_KHR_swapchain", c"VK_EXT_extended_dynamic_state3"], ); let queue = unsafe { dev.get_device_queue(rcs_queue_inx, 0) }; let cmd_pool = make_command_pool(&dev, rcs_queue_inx); let cmd_buf = alloc_cmd_buf(&dev, cmd_pool); let host_visible_inx = find_host_visible(&instance, &pdev).expect("No host visible memory found"); let host_invisible_inx = find_host_invisible(&instance, &pdev).expect("No host invisible memory found"); let mesh_mem = mem_alloc(&dev, host_visible_inx, MESH_SIZE); // Max viewport size is 3440x1440 let depth_mem = mem_alloc( &dev, host_invisible_inx, (MAX_WIDTH * MAX_HEIGHT * 8) as u64, ); let mut depth_img = make_depth_img( &dev, host_invisible_inx, width, height, depth_mem, rcs_queue_inx, ); let mesh_buf = alloc_buf( &dev, &mesh_mem, MESH_SIZE, vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::STORAGE_BUFFER, ); let mesh_mem = buf_to_ptr(&dev, &mesh_mem, &mesh_buf); unsafe { std::ptr::copy(POSITIONS.as_ptr(), mesh_mem as *mut f32, POSITIONS.len()); } let (skybox_image, skybox_image_view, skybox_sampler) = { let qf_idxs = [rcs_queue_inx]; let create_info = vk::ImageCreateInfo::default() .flags(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::GENERAL) .queue_family_indices(&qf_idxs); let image = unsafe { dev.create_image(&create_info, None) }.expect("Failed to create image"); 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), ); let image_view = unsafe { dev.create_image_view(&create_info, None) } .expect("Failed to create image view"); 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); let sampler = unsafe { dev.create_sampler(&create_info, None) }.expect("Failed to create sampler"); (image, image_view, sampler) }; let skybox_mem = mem_alloc(&dev, host_visible_inx, 3 * 2048 * 2048 * 6); let skybox_buf = alloc_buf( &dev, &skybox_mem, 3 * 2048 * 2048 * 6, vk::BufferUsageFlags::TRANSFER_SRC, ); let skybox_ptr = buf_to_ptr(&dev, &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 vert_shader_bin = std::fs::read("shaders/vert.spv").unwrap(); let frag_shader_bin = std::fs::read("shaders/frag.spv").unwrap(); let vert_shader = unsafe { dev.create_shader_module( &vk::ShaderModuleCreateInfo { code_size: vert_shader_bin.len(), p_code: vert_shader_bin.as_ptr() as *const u32, ..Default::default() }, None, ) .expect("Failed to create vertex shader module") }; let frag_shader = unsafe { dev.create_shader_module( &vk::ShaderModuleCreateInfo { code_size: frag_shader_bin.len(), p_code: frag_shader_bin.as_ptr() as *const u32, ..Default::default() }, None, ) .expect("Failed to create fragment shader module") }; let pass = setup_render_pass(&dev); let pipe_layout = setup_pipe_layout(&dev); let pipe = setup_pipeline(&dev, &vert_shader, &frag_shader, &pass, &pipe_layout); let surface_loader = surface::Instance::new(&entry, &instance); let swapchain_loader = swapchain::Device::new(&instance, &dev); let (mut swapchain, mut extents) = setup_swapchain( &pdev, &dev, &surface, &surface_loader, &swapchain_loader, &instance, width, height, ); let desc_pool = setup_desc_pool(&dev); let mut swap_images = make_swap_images(&dev, &swapchain, &swapchain_loader); let mut swap_views = make_swap_views(&dev, &swap_images, vk::Format::B8G8R8A8_UNORM); let mut depth_view = make_depth_view(&dev, &depth_img, vk::Format::D32_SFLOAT); let mut framebufs = make_framebufs(&dev, &swap_views, &depth_view, &pass, width, height); let desc_sets = make_desc_sets(&dev, &desc_pool); write_desc_sets(&dev, &desc_sets, &mesh_buf, skybox_image_view); let sem_avail = make_sem(&dev); let sem_finish = make_sem(&dev); let fence_flight = make_fence(&dev); let mut event_pump = sdl_context.event_pump().expect("Failed to get event pump"); let mut camera = Camera { origin: Vector3 { x: 0.0, y: 0.0, z: 0.0, }, rotation: Vector3 { x: 0.0, y: 0.0, z: 0.0, }, }; let mut running = true; while running { let now = Instant::now(); for event in event_pump.poll_iter() { match event { Event::Quit { .. } => running = false, Event::Window { win_event: WindowEvent::Resized(w, h), .. } => { width = w as u32; height = h as u32; unsafe { dev.device_wait_idle() .expect("Failed to wait for device idle"); swapchain_loader.destroy_swapchain(swapchain, None); } (swapchain, _) = setup_swapchain( &pdev, &dev, &surface, &surface_loader, &swapchain_loader, &instance, width, height, ); swap_images = make_swap_images(&dev, &swapchain, &swapchain_loader); swap_views = make_swap_views(&dev, &swap_images, vk::Format::B8G8R8A8_UNORM); depth_img = make_depth_img( &dev, host_invisible_inx, width, height, depth_mem, rcs_queue_inx, ); depth_view = make_depth_view(&dev, &depth_img, vk::Format::D32_SFLOAT); framebufs = make_framebufs(&dev, &swap_views, &depth_view, &pass, width, height); } // We do this key here and not in `handle_cont_key()` because we don't want key // repeat, just a single press Event::KeyDown { keycode: Some(Keycode::ESCAPE), repeat: false, .. } => { mouse.set_relative_mouse_mode(!mouse.relative_mouse_mode()); } Event::MouseMotion { window_id, xrel, yrel, .. } if mouse.relative_mouse_mode() => { // We only wanna do movement if the mouse is in relative mode (ie. its pinned to // the center of the window and hidden) camera.rotation.y -= xrel as f32 * ROT_MOUSE_SCALE; camera.rotation.x -= yrel as f32 * ROT_MOUSE_SCALE; mouse.warp_mouse_in_window(&window, width as i32 / 2, height as i32 / 2); } _ => {} } } event_pump .keyboard_state() .pressed_scancodes() .filter_map(Keycode::from_scancode) .for_each(|k| handle_cont_key(k, &mut camera, &mouse)); wait_for_fence(&dev, &fence_flight); reset_fence(&dev, &fence_flight); let img_inx = ack_next_img( &dev, &swapchain_loader, &swapchain, &sem_avail, &fence_flight, ); start_cmd_buf(&dev, &cmd_buf); record_commands( &dev, &cmd_buf, &framebufs[img_inx as usize], &pass, &pipe_layout, width, height, &pipe, &desc_sets, &camera, &skybox_buf, &skybox_image, ); end_cmd_buf(&dev, &cmd_buf); submit_queue( &dev, &queue, &cmd_buf, &sem_avail, &sem_finish, &fence_flight, ); queue_present(&swapchain_loader, &queue, &swapchain, img_inx, &sem_finish); let elapsed = now.elapsed(); let delay = (1_000_000u128 / 60).saturating_sub(elapsed.as_micros()); thread::sleep(Duration::from_micros(delay as u64)); } }