iv/src/renderer.rs
Steins7 6aa5e8e3c0 Fixed framebuffer error
* tweaked swap_system acquire_frame() function
* moved fence waiting in acquire_frame()
* cleaned minor details
2021-02-02 11:23:20 +01:00

278 lines
8.5 KiB
Rust

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
iter,
cell::RefCell,
};
use crate::{
io::Output,
utils::Triangle,
};
mod gpu;
use self::gpu::Gpu;
mod swap_system;
use self::swap_system::SwapSystem;
mod pipeline;
use self::pipeline::Pipeline;
//--Renderer implementation-------------------------------------------------------------------------
#[derive(Debug)]
pub struct Renderer<B: gfx_hal::Backend> {
instance: ManuallyDrop<B::Instance>,
gpu: ManuallyDrop<Gpu<B>>,
swap_systems: Vec<SwapSystem<B>>,
pipelines: Vec<Pipeline<B>>,
}
impl<B> Drop for Renderer<B>
where
B: gfx_hal::Backend,
{
fn drop(&mut self) {
use gfx_hal::{
Instance,
device::Device,
};
debug!("Dropping Pipelines...");
for pipeline in self.pipelines.drain(..) {
pipeline.drop(&mut self.gpu);
}
debug!("Waiting for device to idle...");
let _ = self.gpu
.device()
.wait_idle();
info!("Dropping Renderer...");
unsafe {
for mut swap_system in self.swap_systems.drain(..) {
self.instance.destroy_surface(swap_system.drop(&mut self.gpu));
}
ManuallyDrop::drop(&mut self.gpu);
ManuallyDrop::drop(&mut self.instance);
}
trace!("Renderer dropped !");
}
}
impl<B> Renderer<B>
where
B: gfx_hal::Backend,
{
pub fn new<'a, W: 'a, O: 'a, I>(outputs: &mut I) -> Result<Renderer<B>, &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
I: Iterator<Item = &'a RefCell<O>>,
{
use gfx_hal::Instance;
info!("Creating renderer...");
let instance = B::Instance::create("IV", 1)
.map_err(|_| "Could not create instance")?;
let (mut gpu, mut surfaces) = Gpu::new(&instance, outputs)
.map_err(|err| err)?;
let swap_systems = {
surfaces
.drain(..)
.map(|surface| SwapSystem::new(&mut gpu, surface))
.collect::<Result<Vec<_>, &str>>()?
};
let pipelines = vec!(Pipeline::new(&mut gpu, &swap_systems[0]) //TODO improve that
.map_err(|err| err)?);
debug!("Renderer created !");
Ok( Renderer {
instance: ManuallyDrop::new(instance),
gpu: ManuallyDrop::new(gpu),
swap_systems,
pipelines,
})
}
pub fn draw_clear_frame<W, O>(&mut self, output: &RefCell<O>, color: [f32; 4])
-> Result<(), &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
use gfx_hal::{
window::AcquireError,
device::Device,
queue::Submission,
};
let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()];
let mut frame = match swap_system.acquire_frame(&self.gpu) {
Ok(frame) => frame,
Err(err) => match err {
AcquireError::NotReady => {
return Err("Frame acquisition failed because all Frames are in use");
},
AcquireError::OutOfDate => {
swap_system.recreate(&mut self.gpu)?;
debug!("SwapSystem : {:#?}", swap_system);
return Ok(());
},
_ => Err("Could not acquire Frame from SwapSystem")?,
}};
trace!("Waiting for Frame...");
unsafe {
let _ = self.gpu.device()
.wait_for_fence(&frame.fences[0], !0)
.map_err(|_| "Failed to wait for Fence")?;
let _ = self.gpu.device()
.reset_fence(&frame.fences[0])
.map_err(|_| "Failed to reset fence")?;
}
trace!("Recording CommandBuffer...");
unsafe {
use gfx_hal::command::{
CommandBufferFlags,
SubpassContents,
ClearValue,
ClearColor,
CommandBuffer,
};
frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
let clear_value = ClearValue {color: ClearColor{float32: color}};
frame.command_buffer.begin_render_pass(
&swap_system.render_pass,
&frame.framebuffer.as_ref().unwrap(),
swap_system.render_area,
iter::once(clear_value),
SubpassContents::Inline,
);
frame.command_buffer.end_render_pass();
frame.command_buffer.finish();
}
trace!("Submiting to queue...");
let submission = Submission {
command_buffers: iter::once(&*frame.command_buffer),
wait_semaphores: None,
signal_semaphores: iter::once(&frame.signal_semaphores[0]),
};
unsafe {
use gfx_hal::queue::CommandQueue;
self.gpu.queue_mut().submit(submission, Some(&frame.fences[0]));
}
let result = swap_system.present_frame(frame, &mut self.gpu);
if result.is_err() {
swap_system.recreate(&mut self.gpu).unwrap();
}
Ok(())
}
pub fn draw_triangle_frame<W, O>(&mut self,
output: &RefCell<O>,
triangle: Triangle,
colors: [[f32; 3]; 3])
-> Result<(), &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
use gfx_hal::{
window::AcquireError,
queue::Submission,
};
let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()];
let mut frame = match swap_system.acquire_frame(&self.gpu) {
Ok(frame) => frame,
Err(err) => match err {
AcquireError::NotReady => {
return Err("Frame acquisition failed because all Frames are in use");
},
AcquireError::OutOfDate => {
swap_system.recreate(&mut self.gpu)?;
debug!("SwapSystem : {:#?}", swap_system);
return Ok(());
},
_ => Err("Could not acquire Frame from SwapSystem")?,
}};
trace!("Uploading triangle data...");
let points = triangle.points_flat();
self.pipelines[0].write_vertex_buffer(&self.gpu, 0, (&points).to_vec())?; //TODO meh
let colors_flat = colors.iter().flatten().copied().collect();
self.pipelines[0].write_vertex_buffer(&self.gpu, 1, colors_flat)?;
trace!("Recording CommandBuffer...");
unsafe {
use gfx_hal::command::{
CommandBufferFlags,
SubpassContents,
ClearValue,
ClearColor,
CommandBuffer,
};
frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
const TRIANGLE_CLEAR: ClearValue =
ClearValue {color : ClearColor{float32 : [0.5, 0.5, 0.5, 1.0]}};
frame.command_buffer.begin_render_pass(
&swap_system.render_pass,
&frame.framebuffer.as_ref().unwrap(),
swap_system.render_area,
iter::once(TRIANGLE_CLEAR),
SubpassContents::Inline,
);
frame.command_buffer.bind_graphics_pipeline(self.pipelines[0].raw_pipeline());
// storing const data via the CommandBuffer
//let buffer_ref: &B::Buffer = &self.buffer;
//let buffers: Vec<[_; 1]> = vec![(buffer_ref, 0)].into();
frame.command_buffer.bind_vertex_buffers(0, self.pipelines[0].raw_vertex_buffers());
frame.command_buffer.draw(0..3, 0..1);
frame.command_buffer.end_render_pass();
frame.command_buffer.finish();
}
trace!("Submiting to queue...");
let submission = Submission {
command_buffers: iter::once(&*frame.command_buffer),
wait_semaphores: None,
signal_semaphores: iter::once(&frame.signal_semaphores[0]),
};
unsafe {
use gfx_hal::queue::CommandQueue;
self.gpu.queue_mut().submit(submission, Some(&frame.fences[0]));
}
let result = swap_system.present_frame(frame, &mut self.gpu);
if result.is_err() {
swap_system.recreate(&mut self.gpu).unwrap();
}
Ok(())
}
}