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.
416 lines
9.9 KiB
416 lines
9.9 KiB
#[macro_use] |
|
mod util; |
|
|
|
mod conf; |
|
mod hal; |
|
mod render; |
|
//mod vire; |
|
|
|
use crate::{ |
|
render::*, |
|
util::{log, meta}, |
|
}; |
|
|
|
use ash::{version::DeviceV1_0, vk}; |
|
use cgmath::{prelude::*, Matrix4, Point3, Rad, Vector2, Vector3}; |
|
use std::rc::Rc; |
|
|
|
struct Pipelines { |
|
main: Rc<Pipeline>, |
|
} |
|
|
|
struct SwapchainData<'a> { |
|
swapchain: Rc<Swapchain>, |
|
image_f: Vec<Option<&'a Fence>>, |
|
descriptor_pool: Rc<DescriptorPool>, |
|
cmd_pool: Rc<CommandPool>, |
|
} |
|
|
|
impl Pipelines { |
|
fn create_from(mut pipelines: Vec<Rc<Pipeline>>) -> Self { |
|
let main = pipelines.pop().unwrap(); |
|
Self { main } |
|
} |
|
} |
|
|
|
impl SwapchainData<'_> { |
|
pub fn create( |
|
device: Rc<Device>, |
|
phys_device: &PhysicalDevice, |
|
surface: Rc<Surface>, |
|
shader_vert: Rc<ShaderModule>, |
|
shader_frag: Rc<ShaderModule>, |
|
layout: Rc<PipelineLayout>, |
|
vertex_buffer: Rc<Buffer>, |
|
index_buffer: Rc<Buffer>, |
|
queue_graphics: &Queue, |
|
queue_surface: &Queue, |
|
conf: &render::Conf, |
|
) -> Result<Self, ErrBufferCreate> { |
|
let swapchain = Swapchain::create( |
|
device.clone(), |
|
&phys_device, |
|
surface, |
|
conf, |
|
queue_graphics, |
|
queue_surface, |
|
)?; |
|
|
|
let images = Swapchain::get_images(swapchain.clone())?; |
|
|
|
let image_f = vec![None; images.len()]; |
|
|
|
let image_views = |
|
ImageView::create_all(device.clone(), &images, swapchain.format)?; |
|
|
|
let render_pass = RenderPass::create(device.clone(), swapchain.format)?; |
|
|
|
let pipelines = Pipeline::create_all( |
|
device.clone(), |
|
&[ |
|
PipelineCreateInfo::info_basic( |
|
shader_vert, |
|
shader_frag, |
|
layout.clone(), |
|
render_pass.clone(), |
|
swapchain.extent, |
|
), |
|
], |
|
)?; |
|
|
|
let pipelines = Pipelines::create_from(pipelines); |
|
|
|
let framebuffers = Framebuffer::create_all( |
|
device.clone(), |
|
render_pass.clone(), |
|
&image_views, |
|
swapchain.extent, |
|
)?; |
|
|
|
let uniform_buffers = |
|
framebuffers |
|
.iter() |
|
.map(|_| Buffer::create_uniform(device.clone(), phys_device)) |
|
.collect::<Result<_, _>>()?; |
|
|
|
let descriptor_pool = DescriptorPool::create( |
|
device.clone(), |
|
uniform_buffers, |
|
layout.descriptor.clone(), |
|
)?; |
|
|
|
let cmd_pool = CommandPool::create_graphics( |
|
device, |
|
queue_graphics.index, |
|
&framebuffers, |
|
render_pass, |
|
swapchain.extent, |
|
|cmd, framebuffer_num| { |
|
cmd.bind_pipeline(pipelines.main.clone()); |
|
cmd.bind_vertex_buffer(vertex_buffer.clone()); |
|
cmd.bind_index_buffer(index_buffer.clone()); |
|
cmd.bind_descriptor_pool( |
|
descriptor_pool.clone(), |
|
layout.clone(), |
|
framebuffer_num, |
|
); |
|
cmd.draw(INDICES.len()); |
|
}, |
|
)?; |
|
|
|
Ok(Self { swapchain, image_f, descriptor_pool, cmd_pool }) |
|
} |
|
} |
|
|
|
fn draw_frame<'a>( |
|
sc_data: &mut SwapchainData<'a>, |
|
device: &Device, |
|
image_avail_s: &Semaphore, |
|
render_fini_s: &Semaphore, |
|
frame_f: &'a Fence, |
|
queue_graphics: &Queue, |
|
queue_surface: &Queue, |
|
time_ms: u128, |
|
) -> Result<(), vk::Result> { |
|
let cmd_buffers = sc_data.cmd_pool.buf_handles(); |
|
|
|
let fences = [**frame_f]; |
|
|
|
unsafe { |
|
device.wait_for_fences(&fences, true, u64::max_value())?; |
|
} |
|
|
|
let image_index = unsafe { |
|
device |
|
.swapchain_ext |
|
.acquire_next_image( |
|
**sc_data.swapchain, |
|
u64::max_value(), |
|
**image_avail_s, |
|
vk::Fence::null(), |
|
)? |
|
.0 as usize |
|
}; |
|
|
|
if let Some(fence) = sc_data.image_f[image_index] { |
|
let fences = [**fence]; |
|
unsafe { |
|
device.wait_for_fences(&fences, true, u64::max_value())?; |
|
} |
|
} |
|
|
|
sc_data.image_f[image_index] = Some(frame_f); |
|
|
|
let uniforms = Uniforms { |
|
object: |
|
Matrix4::from_angle_z(Rad::full_turn() * time_ms as f32 / 10_000.0), |
|
camera: Matrix4::look_at( |
|
Point3::new(2.0, 2.0, 2.0), |
|
Point3::new(0.0, 0.0, 0.0), |
|
Vector3::new(0.0, 0.0, 1.0), |
|
), |
|
projection: |
|
cgmath::perspective( |
|
Rad::turn_div_4(), |
|
sc_data.swapchain.extent.width as f32 / |
|
sc_data.swapchain.extent.height as f32, |
|
0.01, |
|
100_000.0, |
|
) * |
|
Matrix4::new( |
|
1.0, 0.0, 0.0, 0.0, |
|
0.0, -1.0, 0.0, 0.0, |
|
0.0, 0.0, 1.0, 0.0, |
|
0.0, 0.0, 0.0, 1.0, |
|
), |
|
}; |
|
|
|
sc_data.descriptor_pool.buffers[image_index].write_data(&[uniforms])?; |
|
|
|
let wait_semaphores = [**image_avail_s]; |
|
let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; |
|
|
|
let signal_semaphores = [**render_fini_s]; |
|
|
|
let submit_cmd_buffers = &cmd_buffers[image_index..=image_index]; |
|
|
|
let submit_info = [ |
|
vk::SubmitInfo { |
|
wait_semaphore_count: wait_semaphores.len() as u32, |
|
p_wait_semaphores: wait_semaphores.as_ptr(), |
|
p_wait_dst_stage_mask: wait_stages.as_ptr(), |
|
command_buffer_count: submit_cmd_buffers.len() as u32, |
|
p_command_buffers: submit_cmd_buffers.as_ptr(), |
|
signal_semaphore_count: signal_semaphores.len() as u32, |
|
p_signal_semaphores: signal_semaphores.as_ptr(), |
|
..Default::default() |
|
} |
|
]; |
|
|
|
unsafe { |
|
device.reset_fences(&fences)?; |
|
device.queue_submit(**queue_graphics, &submit_info, **frame_f)?; |
|
} |
|
|
|
let swapchains = [**sc_data.swapchain]; |
|
let image_indices = [image_index as u32]; |
|
|
|
let present_info = vk::PresentInfoKHR { |
|
wait_semaphore_count: signal_semaphores.len() as u32, |
|
p_wait_semaphores: signal_semaphores.as_ptr(), |
|
swapchain_count: swapchains.len() as u32, |
|
p_swapchains: swapchains.as_ptr(), |
|
p_image_indices: image_indices.as_ptr(), |
|
..Default::default() |
|
}; |
|
|
|
unsafe { |
|
device.swapchain_ext.queue_present(**queue_surface, &present_info)?; |
|
device.queue_wait_idle(**queue_surface)?; |
|
} |
|
|
|
Ok(()) |
|
} |
|
|
|
fn seize_device(lg: &log::Log, device: &Device) { |
|
let seize = unsafe { device.device_wait_idle() }; |
|
if let Err(e) = seize { |
|
lg!(lg, log::Level::Error, "Error seizing renderer state: {}", e); |
|
} |
|
} |
|
|
|
fn fallback_main( |
|
conf: &conf::Conf, |
|
lg: &log::Log, |
|
) -> Result<(), Box<dyn std::error::Error>> { |
|
let start_time = std::time::Instant::now(); |
|
|
|
/* |
|
let main = { |
|
use std::io::prelude::*; |
|
let mut file = std::fs::File::open("main.vire")?; |
|
let mut data = String::new(); |
|
file.read_to_string(&mut data)?; |
|
match vire::parser::datum::Datum::parse(&data) { |
|
Ok(datum) => datum, |
|
Err(res) => { |
|
lg!( |
|
lg, log::Level::Error, "`main.vire': {}", |
|
vire::parser::printable_error(&data, res), |
|
); |
|
Vec::new() |
|
} |
|
} |
|
}; |
|
|
|
vire::interpreter::read_all(lg, &main); |
|
*/ |
|
|
|
let concur_frames = conf.render.concurrent_frames.into(); |
|
|
|
let hal = hal::Context::new()?; |
|
let window = hal::Window::new(&hal, meta::ffi::name(), 640, 480)?; |
|
|
|
let entry = ash::Entry::new()?; |
|
let instance = Instance::create(&conf.render, entry, &window)?; |
|
|
|
let phys_device = PhysicalDevice::get(instance.clone(), &conf.render)?; |
|
|
|
let surface = Surface::create(instance.clone(), &window)?; |
|
|
|
let qf_info = QueueFamilyInfo::collect(&instance, &surface, &phys_device)?; |
|
|
|
let device = Device::create(instance, &phys_device, &qf_info)?; |
|
|
|
let queue_graphics = Queue::get(device.clone(), qf_info.gfx_index); |
|
let queue_surface = Queue::get(device.clone(), qf_info.srf_index); |
|
|
|
let vertex_buffer = Buffer::create_vertex( |
|
device.clone(), |
|
&phys_device, |
|
VERTICES, |
|
&queue_graphics, |
|
)?; |
|
|
|
let index_buffer = Buffer::create_index( |
|
device.clone(), |
|
&phys_device, |
|
INDICES, |
|
&queue_graphics, |
|
)?; |
|
|
|
let image_avail_s = Semaphore::create_all(device.clone(), concur_frames)?; |
|
let render_fini_s = Semaphore::create_all(device.clone(), concur_frames)?; |
|
|
|
let frame_f = Fence::create_all(device.clone(), concur_frames)?; |
|
|
|
let desc_layout = DescriptorSetLayout::create(device.clone())?; |
|
let layout = PipelineLayout::create(desc_layout)?; |
|
|
|
let spir_vert = Spir::read(MAIN_VERT); |
|
let spir_frag = Spir::read(MAIN_FRAG); |
|
|
|
let shader_vert = ShaderModule::create(device.clone(), &spir_vert)?; |
|
let shader_frag = ShaderModule::create(device.clone(), &spir_frag)?; |
|
|
|
let mut sc_data = SwapchainData::create( |
|
device.clone(), |
|
&phys_device, |
|
surface.clone(), |
|
shader_vert.clone(), |
|
shader_frag.clone(), |
|
layout.clone(), |
|
vertex_buffer.clone(), |
|
index_buffer.clone(), |
|
&queue_graphics, |
|
&queue_surface, |
|
&conf.render, |
|
)?; |
|
|
|
let mut cur_c_frame = 0; |
|
|
|
'main_loop: loop { |
|
for event in hal::EventIterator { |
|
match event { |
|
hal::Event::Quit => break 'main_loop, |
|
} |
|
} |
|
|
|
let frame = draw_frame( |
|
&mut sc_data, |
|
&device, |
|
&image_avail_s[cur_c_frame], |
|
&render_fini_s[cur_c_frame], |
|
&frame_f[cur_c_frame], |
|
&queue_graphics, |
|
&queue_surface, |
|
start_time.elapsed().as_millis(), |
|
); |
|
|
|
match frame { |
|
Ok(()) => {} |
|
Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { |
|
seize_device(lg, &device); |
|
sc_data = SwapchainData::create( |
|
device.clone(), |
|
&phys_device, |
|
surface.clone(), |
|
shader_vert.clone(), |
|
shader_frag.clone(), |
|
layout.clone(), |
|
vertex_buffer.clone(), |
|
index_buffer.clone(), |
|
&queue_graphics, |
|
&queue_surface, |
|
&conf.render, |
|
)?; |
|
} |
|
Err(res) => { |
|
lg!(lg, log::Level::Error, "Error rendering frame: {}", res); |
|
} |
|
} |
|
|
|
cur_c_frame = (cur_c_frame + 1) % concur_frames; |
|
} |
|
|
|
seize_device(lg, &device); |
|
|
|
Ok(()) |
|
} |
|
|
|
fn main() { |
|
let lg = log::Log::new(); |
|
|
|
#[cfg(feature = "color-log")] |
|
let lg = lg.insert_mode("Color", log::Color).set_mode("Color").unwrap(); |
|
|
|
let conf = conf::Conf::read("blonkus.yaml").unwrap_or_else(|err| { |
|
let level = match err { |
|
conf::ErrConfLoad::NoFile => log::Level::Notice, |
|
_ => log::Level::Error, |
|
}; |
|
lg!(&lg, level, "{}", err); |
|
lg!(&lg, log::Level::Notice, "Using default configuration."); |
|
conf::Conf::default() |
|
}); |
|
|
|
if let Err(e) = fallback_main(&conf, &lg) { |
|
lg!(&lg, log::Level::Critical, "Uncaught error: {}", e); |
|
} |
|
} |
|
|
|
const VERTICES: &[Vertex] = &[ |
|
Vertex { pos: Vector2::new(-0.5, -0.5), color: Vector3::new(1.0, 0.0, 0.0) }, |
|
Vertex { pos: Vector2::new( 0.5, -0.5), color: Vector3::new(0.0, 1.0, 0.0) }, |
|
Vertex { pos: Vector2::new( 0.5, 0.5), color: Vector3::new(0.0, 0.0, 1.0) }, |
|
Vertex { pos: Vector2::new(-0.5, 0.5), color: Vector3::new(1.0, 1.0, 1.0) }, |
|
]; |
|
|
|
const INDICES: &[u16] = &[0, 1, 2, 2, 3, 0]; |
|
|
|
const MAIN_VERT: &[u8] = |
|
include_bytes!(concat!(env!("OUT_DIR"), "/main.vert.o")); |
|
const MAIN_FRAG: &[u8] = |
|
include_bytes!(concat!(env!("OUT_DIR"), "/main.frag.o")); |
|
|
|
// EOF
|
|
|