vk: start to redo hello_triangle to be simpler

This commit is contained in:
chyyran 2023-01-03 00:55:35 -05:00
parent 4393f5c871
commit 1ffdefd4e8
9 changed files with 541 additions and 23 deletions

View file

@ -32,7 +32,7 @@ mod tests {
None,
)
.unwrap();
// let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new(
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// Some(&FilterChainOptions {
// use_deferred_context: true,
@ -40,7 +40,7 @@ mod tests {
// )
// .unwrap();
// let sample = hello_triangle::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
hello_triangle::main(sample).unwrap();
}

View file

@ -0,0 +1,46 @@
use ash::extensions::ext::DebugUtils;
use ash::prelude::VkResult;
use ash::vk;
use ash::vk::{DebugUtilsMessengerEXT, PFN_vkDebugUtilsMessengerCallbackEXT};
pub struct VulkanDebug {
loader: DebugUtils,
messenger: DebugUtilsMessengerEXT
}
impl VulkanDebug {
pub fn new(entry: &ash::Entry, instance: &ash::Instance, callback: PFN_vkDebugUtilsMessengerCallbackEXT) -> VkResult<VulkanDebug>{
let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
.message_severity(
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR
| vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
| vk::DebugUtilsMessageSeverityFlagsEXT::INFO,
)
.message_type(
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
)
.pfn_user_callback(callback);
let debug_utils_loader = DebugUtils::new(entry, instance);
unsafe {
let debug_call_back = debug_utils_loader
.create_debug_utils_messenger(&debug_info, None)?;
Ok(VulkanDebug {
loader: debug_utils_loader,
messenger: debug_call_back
})
}
}
}
impl Drop for VulkanDebug {
fn drop(&mut self) {
unsafe {
self.loader.destroy_debug_utils_messenger(self.messenger, None);
}
}
}

View file

@ -0,0 +1,81 @@
pub mod vulkan_base;
mod debug;
mod physicaldevice;
mod surface;
use winit::event::{Event, VirtualKeyCode, ElementState, KeyboardInput, WindowEvent};
use winit::event_loop::{EventLoop, ControlFlow, EventLoopBuilder};
use winit::platform::windows::EventLoopBuilderExtWindows;
use crate::filter_chain::FilterChainVulkan;
use crate::hello_triangle::surface::VulkanSurface;
use crate::hello_triangle::vulkan_base::VulkanBase;
// Constants
const WINDOW_TITLE: &'static str = "librashader Vulkan";
const WINDOW_WIDTH: u32 = 800;
const WINDOW_HEIGHT: u32 = 600;
struct VulkanWindow;
impl VulkanWindow {
fn init_window(event_loop: &EventLoop<()>) -> winit::window::Window {
winit::window::WindowBuilder::new()
.with_title(WINDOW_TITLE)
.with_inner_size(winit::dpi::LogicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT))
.build(event_loop)
.expect("Failed to create window.")
}
pub fn main_loop(event_loop: EventLoop<()>) {
event_loop.run(move |event, _, control_flow| {
match event {
| Event::WindowEvent { event, .. } => {
match event {
| WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit
},
| WindowEvent::KeyboardInput { input, .. } => {
match input {
| KeyboardInput { virtual_keycode, state, .. } => {
match (virtual_keycode, state) {
| (Some(VirtualKeyCode::Escape), ElementState::Pressed) => {
dbg!();
*control_flow = ControlFlow::Exit
},
| _ => {},
}
},
}
},
| _ => {},
}
},
_ => (),
}
})
}
}
pub struct VulkanDraw {
surface: VulkanSurface,
base: VulkanBase,
}
pub fn main(vulkan: VulkanBase, filter_chain: FilterChainVulkan) {
let event_loop = EventLoopBuilder::new()
.with_any_thread(true)
.with_dpi_aware(true)
.build();
let window = VulkanWindow::init_window(&event_loop);
let surface = VulkanSurface::new(&vulkan, &window)
.unwrap();
let vulkan = VulkanDraw {
surface,
base: vulkan
};
VulkanWindow::main_loop(event_loop);
}

View file

@ -0,0 +1,151 @@
use std::ffi::CStr;
use ash::vk;
pub struct QueueFamilyIndices {
graphics_family: Option<u32>,
}
impl QueueFamilyIndices {
pub fn is_complete(&self) -> bool {
self.graphics_family.is_some()
}
pub fn graphics_family(&self) -> u32 {
self.graphics_family.unwrap()
}
}
pub(crate) fn pick_physical_device(instance: &ash::Instance) -> vk::PhysicalDevice {
let physical_devices = unsafe {
instance
.enumerate_physical_devices()
.expect("Failed to enumerate Physical Devices!")
};
let mut result = None;
for &physical_device in physical_devices.iter() {
if is_physical_device_suitable(instance, physical_device) {
if result.is_none() {
result = Some(physical_device)
}
}
}
match result {
None => panic!("Failed to find a suitable GPU!"),
Some(physical_device) => physical_device,
}
}
fn is_physical_device_suitable(
instance: &ash::Instance,
physical_device: vk::PhysicalDevice,
) -> bool {
let device_properties = unsafe { instance.get_physical_device_properties(physical_device) };
let device_features = unsafe { instance.get_physical_device_features(physical_device) };
let device_queue_families =
unsafe { instance.get_physical_device_queue_family_properties(physical_device) };
let device_type = match device_properties.device_type {
vk::PhysicalDeviceType::CPU => "Cpu",
vk::PhysicalDeviceType::INTEGRATED_GPU => "Integrated GPU",
vk::PhysicalDeviceType::DISCRETE_GPU => "Discrete GPU",
vk::PhysicalDeviceType::VIRTUAL_GPU => "Virtual GPU",
vk::PhysicalDeviceType::OTHER => "Unknown",
_ => panic!(),
};
let device_name = unsafe { CStr::from_ptr(device_properties.device_name.as_ptr()) };
let device_name = device_name.to_string_lossy();
println!(
"\tDevice Name: {}, id: {}, type: {}",
device_name, device_properties.device_id, device_type
);
println!(
"\tAPI Version: {}",
device_properties.api_version
);
println!("\tSupport Queue Family: {}", device_queue_families.len());
println!("\t\tQueue Count | Graphics, Compute, Transfer, Sparse Binding");
for queue_family in device_queue_families.iter() {
let is_graphics_support = if queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
{
"support"
} else {
"unsupport"
};
let is_compute_support = if queue_family.queue_flags.contains(vk::QueueFlags::COMPUTE) {
"support"
} else {
"unsupport"
};
let is_transfer_support = if queue_family.queue_flags.contains(vk::QueueFlags::TRANSFER)
{
"support"
} else {
"unsupport"
};
let is_sparse_support = if queue_family
.queue_flags
.contains(vk::QueueFlags::SPARSE_BINDING)
{
"support"
} else {
"unsupport"
};
println!(
"\t\t{}\t | {}, {}, {}, {}",
queue_family.queue_count,
is_graphics_support,
is_compute_support,
is_transfer_support,
is_sparse_support
);
}
// there are plenty of features
println!(
"\tGeometry Shader support: {}",
if device_features.geometry_shader == 1 {
"support"
} else {
"unsupported"
}
);
let indices = find_queue_family(instance, physical_device);
return indices.is_complete();
}
pub fn find_queue_family(
instance: &ash::Instance,
physical_device: vk::PhysicalDevice,
) -> QueueFamilyIndices {
let queue_families =
unsafe { instance.get_physical_device_queue_family_properties(physical_device) };
let mut queue_family_indices = QueueFamilyIndices {
graphics_family: None,
};
let mut index = 0;
for queue_family in queue_families.iter() {
if queue_family.queue_count > 0
&& queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
{
queue_family_indices.graphics_family = Some(index);
}
if queue_family_indices.is_complete() {
break;
}
index += 1;
}
queue_family_indices
}

View file

@ -0,0 +1,60 @@
use ash::prelude::VkResult;
use ash::vk;
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
use crate::hello_triangle::vulkan_base::VulkanBase;
pub struct VulkanSurface {
surface_loader: ash::extensions::khr::Surface,
surface: vk::SurfaceKHR,
present_queue: vk::Queue
}
impl VulkanSurface {
pub fn new(base: &VulkanBase,
window: &winit::window::Window) -> VkResult<VulkanSurface>
{
let surface = unsafe {
ash_window::create_surface(
&base.entry,
&base.instance,
window.raw_display_handle(),
window.raw_window_handle(),
None,
)?
};
let surface_loader = ash::extensions::khr::Surface::new(&base.entry, &base.instance);
let present_queue = unsafe {
let queue_family = base.instance
.get_physical_device_queue_family_properties(base.physical_device)
.iter()
.enumerate()
.find_map(|(index, info)| {
let supports_graphic_and_surface =
info.queue_flags.contains(vk::QueueFlags::GRAPHICS)
&& surface_loader
.get_physical_device_surface_support(
base.physical_device,
index as u32,
surface,
)
.unwrap();
if supports_graphic_and_surface {
Some(index)
} else {
None
}
})
.expect("couldn't find suitable device");
base.device.get_device_queue(queue_family as u32, 0)
};
Ok(VulkanSurface {
surface,
surface_loader,
present_queue
})
}
}

View file

@ -0,0 +1,165 @@
use std::borrow::Cow;
use std::error::Error;
use ash::vk;
use std::ffi::{CStr, CString};
use ash::prelude::VkResult;
use crate::filter_chain::Vulkan;
use crate::hello_triangle::debug::VulkanDebug;
use crate::hello_triangle::physicaldevice::{find_queue_family, pick_physical_device};
use crate::hello_triangle::surface::VulkanSurface;
const WINDOW_TITLE: &'static str = "librashader Vulkan";
pub struct VulkanBase {
pub entry: ash::Entry,
pub instance: ash::Instance,
pub device: ash::Device,
pub graphics_queue: vk::Queue,
pub debug: VulkanDebug,
pub physical_device: vk::PhysicalDevice,
pub mem_props: vk::PhysicalDeviceMemoryProperties,
}
impl VulkanBase {
pub fn new(entry: ash::Entry) -> VkResult<VulkanBase> {
let app_name = CString::new(WINDOW_TITLE).unwrap();
let engine_name = CString::new("librashader").unwrap();
let app_info = vk::ApplicationInfo::builder()
.application_name(&app_name)
.engine_name(&engine_name)
.engine_version(0)
.application_version(0)
.api_version(vk::make_api_version(0, 1, 3, 0))
.build();
// todo: make this xplat
let extensions = [
ash::extensions::khr::Surface::name().as_ptr(),
ash::extensions::khr::Win32Surface::name().as_ptr(),
ash::extensions::ext::DebugUtils::name().as_ptr()
];
let layers = unsafe {
[CStr::from_bytes_with_nul_unchecked(
b"VK_LAYER_KHRONOS_validation\0",
).as_ptr()]
};
let create_info = vk::InstanceCreateInfo::builder()
.application_info(&app_info)
.enabled_layer_names(&layers)
.enabled_extension_names(&extensions)
.build();
let instance = unsafe {
entry.create_instance(&create_info, None)?
};
let debug = VulkanDebug::new(&entry, &instance, Some(vulkan_debug_callback))?;
let physical_device = pick_physical_device(&instance);
let (device, queue) = VulkanBase::create_device(&instance, &physical_device)?;
let mem_props = unsafe {
instance.get_physical_device_memory_properties(physical_device)
};
Ok(VulkanBase {
entry,
instance,
device,
graphics_queue: queue,
physical_device,
mem_props,
debug,
})
}
fn create_device(instance: &ash::Instance, physical_device: &vk::PhysicalDevice) -> VkResult<(ash::Device, vk::Queue)> {
let debug = unsafe {
CStr::from_bytes_with_nul_unchecked(
b"VK_LAYER_KHRONOS_validation\0",
).as_ptr()
};
let indices = find_queue_family(&instance, *physical_device);
let queue_info = vk::DeviceQueueCreateInfo::builder()
.queue_family_index(indices.graphics_family())
.queue_priorities(&[1.0f32])
.build();
let physical_device_features = vk::PhysicalDeviceFeatures::default();
let device_create_info = vk::DeviceCreateInfo::builder()
.queue_create_infos(&[queue_info])
.enabled_layer_names(&[debug])
.enabled_extension_names(&[
ash::extensions::khr::Swapchain::name().as_ptr()
])
.enabled_features(&physical_device_features)
.build();
let device = unsafe {
instance.create_device(*physical_device, &device_create_info, None)?
};
let queue = unsafe { device.get_device_queue(indices.graphics_family(), 0) };
Ok((device, queue))
}
}
unsafe extern "system" fn vulkan_debug_callback(
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
_user_data: *mut std::os::raw::c_void,
) -> vk::Bool32 {
let callback_data = *p_callback_data;
let message_id_number: i32 = callback_data.message_id_number as i32;
let message_id_name = if callback_data.p_message_id_name.is_null() {
Cow::from("")
} else {
CStr::from_ptr(callback_data.p_message_id_name).to_string_lossy()
};
let message = if callback_data.p_message.is_null() {
Cow::from("")
} else {
CStr::from_ptr(callback_data.p_message).to_string_lossy()
};
println!(
"{:?}:\n{:?} [{} ({})] : {}\n",
message_severity,
message_type,
message_id_name,
&message_id_number.to_string(),
message,
);
vk::FALSE
}
impl Drop for VulkanBase {
fn drop(&mut self) {
unsafe {
self.device.destroy_device(None);
self.instance.destroy_instance(None);
}
}
}
impl TryFrom<&VulkanBase> for Vulkan {
type Error = Box<dyn Error>;
fn try_from(value: &VulkanBase) -> Result<Self, Self::Error> {
Vulkan::try_from((value.device.clone(), value.graphics_queue.clone(), value.mem_props))
}
}

View file

@ -203,8 +203,8 @@ pub(crate) fn main(base: ExampleBase, mut filter_chain: FilterChainVulkan) {
base.device
.bind_buffer_memory(vertex_input_buffer, vertex_input_buffer_memory, 0)
.unwrap();
let mut vertex_spv_file = Cursor::new(&include_bytes!("../shader/triangle/vert.spv")[..]);
let mut frag_spv_file = Cursor::new(&include_bytes!("../shader/triangle/frag.spv")[..]);
let mut vertex_spv_file = Cursor::new(&include_bytes!("../../shader/triangle/vert.spv")[..]);
let mut frag_spv_file = Cursor::new(&include_bytes!("../../shader/triangle/frag.spv")[..]);
let vertex_code =
read_spv(&mut vertex_spv_file).expect("Failed to read vertex shader spv file");

View file

@ -7,7 +7,7 @@ mod error;
mod filter_chain;
mod filter_pass;
mod framebuffer;
mod hello_triangle;
mod hello_triangle_old;
mod luts;
mod renderpass;
mod util;
@ -17,31 +17,46 @@ mod samplers;
mod texture;
mod rendertarget;
mod ubo_ring;
mod hello_triangle;
#[cfg(test)]
mod tests {
use super::*;
use crate::filter_chain::FilterChainVulkan;
use crate::filter_chain::{FilterChainVulkan, Vulkan};
use crate::hello_triangle::vulkan_base::VulkanBase;
#[test]
fn triangle_vk() {
let base = hello_triangle::ExampleBase::new(900, 600);
// let mut filter = FilterChainVulkan::load_from_path(
// (base.device.clone(), base.present_queue.clone(), base.device_memory_properties.clone()),
// "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// None
// )
let entry = unsafe {
ash::Entry::load().unwrap()
};
let base = VulkanBase::new(entry).unwrap();
let mut filter = FilterChainVulkan::load_from_path(
(
base.device.clone(),
base.present_queue.clone(),
base.device_memory_properties.clone(),
),
&base,
"../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
None,
)
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
hello_triangle::main(base, filter);
None
).unwrap();
crate::hello_triangle::main(base, filter)
// let base = hello_triangle_old::ExampleBase::new(900, 600);
// // let mut filter = FilterChainVulkan::load_from_path(
// // (base.device.clone(), base.present_queue.clone(), base.device_memory_properties.clone()),
// // "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// // None
// // )
//
// let mut filter = FilterChainVulkan::load_from_path(
// (
// base.device.clone(),
// base.present_queue.clone(),
// base.device_memory_properties.clone(),
// ),
// "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// None,
// )
// // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
// .unwrap();
// hello_triangle_old::main(base, filter);
}
}