You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MineClone/src/main.rs

1184 lines
37 KiB

#![feature(inherent_str_constructors)]
#![allow(unused_variables, unused_mut)]
use ash::Device;
use ash::Entry;
use ash::Instance;
use ash::khr::{surface, swapchain};
use ash::vk;
use std::ffi::CStr;
use std::ffi::CString;
use raw_window_handle::HasDisplayHandle;
use raw_window_handle::HasWindowHandle;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::Window;
const APP_NAME: &str = "MineClone";
const MESH_SIZE: u64 = 36 * 2 * 4 * 4;
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,
];
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::<Vec<_>>();
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: {}",
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<u32> {
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::<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> {
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<u32> {
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 layouts = [storage_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(CStr::from_bytes_with_nul(b"main\0").unwrap());
let frag_stage = vk::PipelineShaderStageCreateInfo::default()
.stage(vk::ShaderStageFlags::FRAGMENT)
.module(frag_shader)
.name(CStr::from_bytes_with_nul(b"main\0").unwrap());
[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::BACK)
.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,
) -> vk::SwapchainKHR {
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");
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(caps.current_extent)
.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
}
fn setup_desc_pool(dev: &Device) -> vk::DescriptorPool {
let pool_size = vk::DescriptorPoolSize::default()
.ty(vk::DescriptorType::STORAGE_BUFFER)
.descriptor_count(1);
let pool_sizes = [pool_size];
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<vk::Image> {
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<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 {
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<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 {
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<vk::DescriptorSet> {
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<vk::DescriptorSet>, mesh_buf: &vk::Buffer) {
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);
unsafe {
dev.update_descriptor_sets(&[buf_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<vk::DescriptorSet>,
camera: &Camera,
) {
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<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();
let screen_res: Vec<u8> = (Vec::<u32>::from([width, height]))
.iter()
.map(|f| f.to_ne_bytes())
.collect::<Vec<_>>()
.into_flattened();
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();
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(),
);
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_key(keycode: Keycode, camera: &mut Camera) {
let mov_scale = 0.01;
let rot_scale = 0.01;
match keycode {
Keycode::W => {
camera.origin.x -= -camera.rotation.y.sin() * mov_scale;
camera.origin.z -= camera.rotation.y.cos() * mov_scale;
}
Keycode::S => {
camera.origin.x += -camera.rotation.y.sin() * mov_scale;
camera.origin.z += camera.rotation.y.cos() * mov_scale;
}
Keycode::A => {
camera.origin.x += camera.rotation.y.cos() * mov_scale;
camera.origin.z += camera.rotation.y.sin() * mov_scale;
}
Keycode::D => {
camera.origin.z -= camera.rotation.y.sin() * mov_scale;
camera.origin.x -= camera.rotation.y.cos() * mov_scale;
}
Keycode::R => {
camera.rotation.x += rot_scale;
}
Keycode::F => {
camera.rotation.x -= rot_scale;
}
Keycode::Q => {
camera.rotation.y += rot_scale;
}
Keycode::E => {
camera.rotation.y -= rot_scale;
}
Keycode::Space => {
camera.origin.y += mov_scale;
}
Keycode::LShift => {
camera.origin.y -= mov_scale;
}
_ => {}
}
}
fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let mut width = 1024;
let mut height = 768;
let max_width = 3440;
let max_height = 1440;
let window = video_subsystem
.window(APP_NAME, width, height)
.vulkan()
.build()
.unwrap();
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);
let 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 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 swapchain = setup_swapchain(
&pdev,
&dev,
&surface,
&surface_loader,
&swapchain_loader,
&instance,
);
let desc_pool = setup_desc_pool(&dev);
let swap_images = make_swap_images(&dev, &swapchain, &swapchain_loader);
let swap_views = make_swap_views(&dev, &swap_images, vk::Format::B8G8R8A8_UNORM);
let depth_view = make_depth_view(&dev, &depth_img, vk::Format::D32_SFLOAT);
let 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);
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 {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. } => running = false,
Event::KeyDown {
keycode: Some(keycode),
..
} => handle_key(keycode, &mut camera),
_ => {}
}
}
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,
);
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);
}
}