Browse Source

correctly handle rendering frames

master
Alison Watson 1 year ago
parent
commit
93731e1b5c
10 changed files with 209 additions and 48 deletions
  1. +79
    -23
      source/main.rs
  2. +5
    -1
      source/render.rs
  3. +3
    -0
      source/render/conf.rs
  4. +31
    -0
      source/render/fence.rs
  5. +2
    -2
      source/render/framebuffer.rs
  6. +34
    -0
      source/render/image.rs
  7. +4
    -4
      source/render/imageview.rs
  8. +29
    -4
      source/render/queue.rs
  9. +7
    -7
      source/render/semaphore.rs
  10. +15
    -7
      source/render/swapchain.rs

+ 79
- 23
source/main.rs View File

@@ -13,30 +13,65 @@ const MAIN_VERT: &'static [u8] =
const MAIN_FRAG: &'static [u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/main.frag.o"));

fn draw_frame(
fn create_semaphores<'a, 'b>(
device: &'a Device<'b>,
num: usize,
) -> Result<Vec<Semaphore<'a, 'b>>, vk::Result> {
(0..num)
.map(|_| Semaphore::create(&device))
.collect()
}

fn create_fences<'a, 'b>(
device: &'a Device<'b>,
num: usize,
) -> Result<Vec<Fence<'a, 'b>>, vk::Result> {
(0..num)
.map(|_| Fence::create(&device))
.collect()
}

fn draw_frame<'a, 'b, 'c>(
device: &Device,
swapchain: &Swapchain,
image_available_s: &Semaphore,
render_finished_s: &Semaphore,
frame_f: &'a Fence<'b, 'c>,
image_f: &mut [Option<&'a Fence<'b, 'c>>],
cmd_buffers: &[CommandBuffer],
queue_graphics: &Queue,
queue_surface: &Queue,
) -> Result<(), vk::Result> {
let fences = [**frame_f];

unsafe {
device.wait_for_fences(&fences, true, u64::max_value())?;
}

let image_index = unsafe {
device.swapchain_ext.acquire_next_image(
**swapchain,
u64::max_value(),
**image_available_s,
vk::Fence::null(),
)?.0
)?.0 as usize
};

if let Some(fence) = image_f[image_index] {
let fences = [**fence];
unsafe {
device.wait_for_fences(&fences, true, u64::max_value())?;
}
}

image_f[image_index] = Some(frame_f);

let wait_semaphores = [**image_available_s];
let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];

let signal_semaphores = [**render_finished_s];

let submit_cmd_buffers = [*cmd_buffers[image_index as usize]];
let submit_cmd_buffers = [*cmd_buffers[image_index]];

let submit_info = [
vk::SubmitInfo {
@@ -52,11 +87,12 @@ fn draw_frame(
];

unsafe {
device.queue_submit(**queue_graphics, &submit_info, vk::Fence::null())?;
device.reset_fences(&fences)?;
device.queue_submit(**queue_graphics, &submit_info, **frame_f)?;
}

let swapchains = [**swapchain];
let image_indices = [image_index];
let image_indices = [image_index as u32];

let present_info = vk::PresentInfoKHR {
wait_semaphore_count: signal_semaphores.len() as u32,
@@ -69,6 +105,7 @@ fn draw_frame(

unsafe {
device.swapchain_ext.queue_present(**queue_surface, &present_info)?;
device.queue_wait_idle(**queue_surface)?;
}

Ok(())
@@ -106,11 +143,12 @@ fn fallback_main(
&qf_info,
)?;

let images = swapchain.get_images()?;

let image_views =
swapchain
.get_images()?
images
.iter()
.map(|&image| ImageView::create(&device, image, swapchain.format))
.map(|image| ImageView::create(&device, image, swapchain.format))
.collect::<Result<Vec<_>, _>>()?;

let shader_vert = ShaderModule::create(&device, &Spir::read(MAIN_VERT))?;
@@ -156,23 +194,41 @@ fn fallback_main(
})
.collect::<Result<(), _>>()?;

let image_available_s = Semaphore::create(&device)?;
let render_finished_s = Semaphore::create(&device)?;
let concur_frames = conf.render.concurrent_frames.into();

let frame = draw_frame(
&device,
&swapchain,
&image_available_s,
&render_finished_s,
&cmd_buffers,
&queue_graphics,
&queue_surface,
);
if let Err(e) = frame {
lg!(lg, Level::Error, "Error rendering frame: {}", e);
}
let image_available_s = create_semaphores(&device, concur_frames)?;
let render_finished_s = create_semaphores(&device, concur_frames)?;

let frame_f = create_fences(&device, concur_frames)?;
let mut image_f = vec![None; images.len()];

let mut cur_c_frame = 0;

std::thread::sleep(std::time::Duration::from_secs(3));
'main_loop: loop {
for event in hal::EventIterator {
match event {
hal::Event::Quit => break 'main_loop,
}
}

let frame = draw_frame(
&device,
&swapchain,
&image_available_s[cur_c_frame],
&render_finished_s[cur_c_frame],
&frame_f[cur_c_frame],
&mut image_f,
&cmd_buffers,
&queue_graphics,
&queue_surface,
);

if let Err(e) = frame {
lg!(lg, Level::Error, "Error rendering frame: {}", e);
}

cur_c_frame = (cur_c_frame + 1) % concur_frames;
}

let seize = unsafe { device.device_wait_idle() };
if let Err(e) = seize {


+ 5
- 1
source/render.rs View File

@@ -1,7 +1,9 @@
mod cmd;
mod conf;
mod device;
mod fence;
mod framebuffer;
mod image;
mod imageview;
mod instance;
mod pipeline;
@@ -17,12 +19,14 @@ pub use self::{
cmd::{CommandBuffer, CommandPool},
conf::{Conf, PresentMode},
device::{Device, PhysicalDevice},
fence::Fence,
framebuffer::Framebuffer,
image::Image,
imageview::ImageView,
instance::Instance,
pipeline::{PipelineLayout, Pipeline, RenderPass},
properties::{ErrNoProperty, ensure_properties},
queue::{Queue, QueueFamilyInfo},
queue::{ErrQueueFamilyCollect, Queue, QueueFamilyInfo},
semaphore::Semaphore,
shader::ShaderModule,
spir::Spir,


+ 3
- 0
source/render/conf.rs View File

@@ -1,4 +1,5 @@
use ash::vk;
use std::num::NonZeroUsize;

serialize! {
conf_enum:
@@ -17,6 +18,7 @@ serialize! {
pub device: usize,
pub validation_layers: bool,
pub swap_mode: PresentMode,
pub concurrent_frames: NonZeroUsize,
}
}

@@ -37,6 +39,7 @@ impl Default for Conf {
device: 0,
validation_layers: cfg!(debug_assertions),
swap_mode: PresentMode::Mailbox,
concurrent_frames: NonZeroUsize::new(2).unwrap(),
}
}
}


+ 31
- 0
source/render/fence.rs View File

@@ -0,0 +1,31 @@
use ash::{version::DeviceV1_0, vk};
use crate::render::Device;

pub struct Fence<'a, 'b> {
device: &'a Device<'b>,
handle: vk::Fence,
}

impl<'a, 'b> Fence<'a, 'b> {
pub fn create(device: &'a Device<'b>) -> Result<Self, vk::Result> {
let create_info = vk::FenceCreateInfo {
flags: vk::FenceCreateFlags::SIGNALED,
..Default::default()
};
let handle = unsafe { device.create_fence(&create_info, None)? };
Ok(Self { device, handle })
}
}

impl Drop for Fence<'_, '_> {
fn drop(&mut self) {
unsafe { self.device.destroy_fence(self.handle, None); }
}
}

impl std::ops::Deref for Fence<'_, '_> {
type Target = vk::Fence;
fn deref(&self) -> &Self::Target { &self.handle }
}

// EOF

+ 2
- 2
source/render/framebuffer.rs View File

@@ -1,5 +1,5 @@
use ash::{version::DeviceV1_0, vk};
use crate::{render::{Device, ImageView, RenderPass}, util::err};
use crate::render::{Device, ImageView, RenderPass};

pub struct Framebuffer<'a, 'b> {
device: &'a Device<'b>,
@@ -12,7 +12,7 @@ impl<'a, 'b> Framebuffer<'a, 'b> {
render_pass: &RenderPass,
image_view: &ImageView,
image_extent: vk::Extent2D,
) -> err::Result<Self> {
) -> Result<Self, vk::Result> {
let attachments = [**image_view];

let create_info = vk::FramebufferCreateInfo {


+ 34
- 0
source/render/image.rs View File

@@ -0,0 +1,34 @@
use ash::{version::DeviceV1_0, vk};
use crate::render::{Device, Swapchain};
use std::marker::PhantomData;

pub struct Image<'a, 'b, 'c> {
owner: Option<PhantomData<&'c Swapchain<'a, 'b>>>,
device: &'a Device<'b>,
handle: vk::Image,
}

impl<'a, 'b, 'c> Image<'a, 'b, 'c> {
pub fn own(
_owner: &'c Swapchain<'a, 'b>,
device: &'a Device<'b>,
handle: vk::Image,
) -> Self {
Self { owner: Some(PhantomData), device, handle }
}
}

impl Drop for Image<'_, '_, '_> {
fn drop(&mut self) {
if self.owner.is_none() {
unsafe { self.device.destroy_image(self.handle, None); }
}
}
}

impl std::ops::Deref for Image<'_, '_, '_> {
type Target = vk::Image;
fn deref(&self) -> &Self::Target { &self.handle }
}

// EOF

+ 4
- 4
source/render/imageview.rs View File

@@ -1,5 +1,5 @@
use ash::{version::DeviceV1_0, vk};
use crate::{render::Device, util::err};
use crate::render::{Device, Image};

pub struct ImageView<'a, 'b> {
device: &'a Device<'b>,
@@ -9,12 +9,12 @@ pub struct ImageView<'a, 'b> {
impl<'a, 'b> ImageView<'a, 'b> {
pub fn create(
device: &'a Device<'b>,
image: vk::Image,
image: &Image,
format: vk::Format,
) -> err::Result<Self> {
) -> Result<Self, vk::Result> {
let create_info = vk::ImageViewCreateInfo {
image,
format,
image: **image,
view_type: vk::ImageViewType::TYPE_2D,
components: vk::ComponentMapping {
r: vk::ComponentSwizzle::IDENTITY,


+ 29
- 4
source/render/queue.rs View File

@@ -1,7 +1,14 @@
use ash::{version::{DeviceV1_0, InstanceV1_0}, vk};
use crate::{render::{Device, Instance, PhysicalDevice, Surface}, util::err};
use crate::render::{Device, Instance, PhysicalDevice, Surface};
use std::marker::PhantomData;

#[derive(Debug)]
pub enum ErrQueueFamilyCollect {
Vk(vk::Result),
NoGfxQueue,
NoSrfQueue,
}

pub struct QueueFamilyInfo {
pub gfx_index: u32,
pub srf_index: u32,
@@ -17,7 +24,7 @@ impl QueueFamilyInfo {
instance: &Instance,
surface: &Surface,
phys_device: &PhysicalDevice,
) -> err::Result<Self> {
) -> Result<Self, ErrQueueFamilyCollect> {
let mut gfx_index = None;
let mut srf_index = None;

@@ -46,8 +53,8 @@ impl QueueFamilyInfo {
}

Ok(Self {
gfx_index: gfx_index.ok_or(err::static_msg("no graphics queue"))?,
srf_index: srf_index.ok_or(err::static_msg("no surface queue"))?,
gfx_index: gfx_index.ok_or(ErrQueueFamilyCollect::NoGfxQueue)?,
srf_index: srf_index.ok_or(ErrQueueFamilyCollect::NoSrfQueue)?,
})
}
}
@@ -64,4 +71,22 @@ impl std::ops::Deref for Queue<'_, '_> {
fn deref(&self) -> &Self::Target { &self.handle }
}

impl std::fmt::Display for ErrQueueFamilyCollect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Vk(res) => res.fmt(f),
Self::NoGfxQueue => f.write_str("Graphics queue not available"),
Self::NoSrfQueue => f.write_str("Surface queue not available"),
}
}
}

impl std::error::Error for ErrQueueFamilyCollect {}

impl From<vk::Result> for ErrQueueFamilyCollect {
fn from(res: vk::Result) -> Self {
Self::Vk(res)
}
}

// EOF

+ 7
- 7
source/render/semaphore.rs View File

@@ -1,26 +1,26 @@
use ash::{version::DeviceV1_0, vk};
use crate::util::err;
use crate::render::Device;

pub struct Semaphore<'a> {
device: &'a ash::Device,
pub struct Semaphore<'a, 'b> {
device: &'a Device<'b>,
handle: vk::Semaphore,
}

impl<'a> Semaphore<'a> {
pub fn create(device: &'a ash::Device) -> err::Result<Self> {
impl<'a, 'b> Semaphore<'a, 'b> {
pub fn create(device: &'a Device<'b>) -> Result<Self, vk::Result> {
let create_info = vk::SemaphoreCreateInfo::default();
let handle = unsafe { device.create_semaphore(&create_info, None)? };
Ok(Self { device, handle })
}
}

impl Drop for Semaphore<'_> {
impl Drop for Semaphore<'_, '_> {
fn drop(&mut self) {
unsafe { self.device.destroy_semaphore(self.handle, None); }
}
}

impl std::ops::Deref for Semaphore<'_> {
impl std::ops::Deref for Semaphore<'_, '_> {
type Target = vk::Semaphore;
fn deref(&self) -> &Self::Target { &self.handle }
}


+ 15
- 7
source/render/swapchain.rs View File

@@ -1,7 +1,12 @@
use ash::vk;
use crate::{
render::{Conf, Device, Instance, PhysicalDevice, QueueFamilyInfo, Surface},
util::err
use crate::render::{
Conf,
Device,
Image,
Instance,
PhysicalDevice,
QueueFamilyInfo,
Surface
};

pub struct Swapchain<'a, 'b> {
@@ -20,7 +25,7 @@ impl<'a, 'b> Swapchain<'a, 'b> {
surface: &Surface,
conf: &Conf,
qf_info: &QueueFamilyInfo,
) -> err::Result<Self> {
) -> Result<Self, vk::Result> {
let capabilities = unsafe {
instance
.surface_ext
@@ -79,7 +84,7 @@ impl<'a, 'b> Swapchain<'a, 'b> {

let min_image_count =
if capabilities.max_image_count > 0 &&
min_image_count > capabilities.max_image_count
min_image_count > capabilities.max_image_count
{
capabilities.max_image_count
} else {
@@ -117,11 +122,14 @@ impl<'a, 'b> Swapchain<'a, 'b> {
Ok(Self { device, handle, format: format.format, extent })
}

pub fn get_images(&self) -> err::Result<Vec<vk::Image>> {
pub fn get_images(&self) -> Result<Vec<Image>, vk::Result> {
let images = unsafe {
self.device.swapchain_ext.get_swapchain_images(self.handle)?
};
Ok(images)
Ok(images
.iter()
.map(|&image| Image::own(self, self.device, image))
.collect())
}
}



Loading…
Cancel
Save