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

#[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