First render !!!
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 1s
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 1s
This commit is contained in:
parent
2590db0a06
commit
c0367144a6
9 changed files with 123 additions and 70 deletions
|
@ -61,6 +61,7 @@ impl ApplicationHandler for App {
|
||||||
Some(render_context) => {
|
Some(render_context) => {
|
||||||
if let Err(error) = render_context.render() {
|
if let Err(error) = render_context.render() {
|
||||||
log::error!("Failed to render with render context : {}", error);
|
log::error!("Failed to render with render context : {}", error);
|
||||||
|
event_loop.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => log::warn!("Window resized but no render context found"),
|
None => log::warn!("Window resized but no render context found"),
|
||||||
|
|
|
@ -34,4 +34,7 @@ pub(self) use vk_command_pool::VkCommandPool;
|
||||||
mod vk_framebuffer;
|
mod vk_framebuffer;
|
||||||
pub(self) use vk_framebuffer::VkFramebuffer;
|
pub(self) use vk_framebuffer::VkFramebuffer;
|
||||||
|
|
||||||
|
mod vk_fence;
|
||||||
|
pub(self) use vk_fence::VkFence;
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
|
@ -12,7 +12,9 @@ pub struct VkCommandPool {
|
||||||
impl VkCommandPool {
|
impl VkCommandPool {
|
||||||
pub fn new(device: &Arc<VkDevice>) -> VkResult<Self> {
|
pub fn new(device: &Arc<VkDevice>) -> VkResult<Self> {
|
||||||
let command_pool_info =
|
let command_pool_info =
|
||||||
vk::CommandPoolCreateInfo::default().queue_family_index(device.queue_family_index);
|
vk::CommandPoolCreateInfo::default()
|
||||||
|
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
|
||||||
|
.queue_family_index(device.queue_family_index);
|
||||||
let command_pool = unsafe {
|
let command_pool = unsafe {
|
||||||
device
|
device
|
||||||
.handle
|
.handle
|
||||||
|
|
30
src/vulkan/vk_fence.rs
Normal file
30
src/vulkan/vk_fence.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use crate::vulkan::VkDevice;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkFence {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub(super) handle: vk::Fence,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkFence {
|
||||||
|
pub fn new(device: &Arc<VkDevice>) -> anyhow::Result<Self> {
|
||||||
|
let fence_info = vk::FenceCreateInfo::default()
|
||||||
|
.flags(vk::FenceCreateFlags::SIGNALED);
|
||||||
|
let fence = unsafe { device.handle.create_fence(&fence_info, None)? };
|
||||||
|
log::debug!("Fence created ({fence:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
handle: fence,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkFence {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.device.handle.destroy_fence(self.handle, None) };
|
||||||
|
log::debug!("Fence destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,18 +46,9 @@ impl VkGraphicsPipeline {
|
||||||
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
||||||
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
|
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
|
||||||
|
|
||||||
let viewport = vk::Viewport::default()
|
|
||||||
.width(swapchain.surface_resolution.width as f32)
|
|
||||||
.height(swapchain.surface_resolution.height as f32)
|
|
||||||
.max_depth(1.0);
|
|
||||||
|
|
||||||
let scissor = vk::Rect2D::default().extent(swapchain.surface_resolution);
|
|
||||||
|
|
||||||
let viewports = [viewport];
|
|
||||||
let scissors = [scissor];
|
|
||||||
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
||||||
.viewports(&viewports)
|
.viewport_count(1)
|
||||||
.scissors(&scissors);
|
.scissor_count(1);
|
||||||
|
|
||||||
let rasterizer = vk::PipelineRasterizationStateCreateInfo::default()
|
let rasterizer = vk::PipelineRasterizationStateCreateInfo::default()
|
||||||
.polygon_mode(vk::PolygonMode::FILL)
|
.polygon_mode(vk::PolygonMode::FILL)
|
||||||
|
@ -77,7 +68,7 @@ impl VkGraphicsPipeline {
|
||||||
vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments);
|
vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments);
|
||||||
|
|
||||||
let dynamic_state = vk::PipelineDynamicStateCreateInfo::default()
|
let dynamic_state = vk::PipelineDynamicStateCreateInfo::default()
|
||||||
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::LINE_WIDTH]);
|
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]);
|
||||||
|
|
||||||
let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default();
|
let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default();
|
||||||
let pipeline_layout = unsafe {
|
let pipeline_layout = unsafe {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::vulkan::{
|
use crate::vulkan::{
|
||||||
VkCommandPool, VkDevice, VkFramebuffer, VkGraphicsPipeline, VkInstance, VkPhysicalDevice,
|
VkCommandPool, VkDevice, VkFence, VkFramebuffer, VkGraphicsPipeline, VkInstance, VkPhysicalDevice,
|
||||||
VkRenderPass, VkSemaphore, VkSurface, VkSwapchain,
|
VkRenderPass, VkSemaphore, VkSurface, VkSwapchain,
|
||||||
};
|
};
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
|
@ -18,6 +18,7 @@ pub struct VkRenderContext {
|
||||||
command_buffers: Vec<vk::CommandBuffer>,
|
command_buffers: Vec<vk::CommandBuffer>,
|
||||||
image_available_semaphore: VkSemaphore,
|
image_available_semaphore: VkSemaphore,
|
||||||
render_finished_semaphore: VkSemaphore,
|
render_finished_semaphore: VkSemaphore,
|
||||||
|
in_flight_fence: VkFence,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VkRenderContext {
|
impl VkRenderContext {
|
||||||
|
@ -36,7 +37,7 @@ impl VkRenderContext {
|
||||||
Some(vk::QueueFlags::GRAPHICS),
|
Some(vk::QueueFlags::GRAPHICS),
|
||||||
Some(&surface),
|
Some(&surface),
|
||||||
)
|
)
|
||||||
.ok_or_else(|| anyhow::anyhow!("Unable to find physical device"))?;
|
.ok_or_else(|| anyhow::anyhow!("Unable to find physical device"))?;
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Selected queue {properties:#?} for physical device {:?}",
|
"Selected queue {properties:#?} for physical device {:?}",
|
||||||
physical_device.properties.device_name_as_c_str()
|
physical_device.properties.device_name_as_c_str()
|
||||||
|
@ -77,50 +78,9 @@ impl VkRenderContext {
|
||||||
.allocate_command_buffers(&command_buffer_info)?
|
.allocate_command_buffers(&command_buffer_info)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Same in VkGraphicsPipeline (TODO: Refactor this)
|
let image_available_semaphore = VkSemaphore::new(&device)?;
|
||||||
let render_area = vk::Rect2D::default().extent(swapchain.surface_resolution);
|
let render_finished_semaphore = VkSemaphore::new(&device)?;
|
||||||
let clear_value = vk::ClearValue::default();
|
let in_flight_fence = VkFence::new(&device)?;
|
||||||
for (index, command_buffer) in command_buffers.iter().enumerate() {
|
|
||||||
let command_buffer_begin_info = vk::CommandBufferBeginInfo::default();
|
|
||||||
unsafe {
|
|
||||||
device
|
|
||||||
.handle
|
|
||||||
.begin_command_buffer(*command_buffer, &command_buffer_begin_info)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let clear_values = [clear_value];
|
|
||||||
let framebuffer = framebuffers[index].as_ref();
|
|
||||||
let render_pass_begin_info = vk::RenderPassBeginInfo::default()
|
|
||||||
.render_pass(render_pass.handle)
|
|
||||||
.framebuffer(framebuffer.handle)
|
|
||||||
.render_area(render_area)
|
|
||||||
.clear_values(&clear_values);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
device.handle.cmd_begin_render_pass(
|
|
||||||
*command_buffer,
|
|
||||||
&render_pass_begin_info,
|
|
||||||
vk::SubpassContents::INLINE,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
device.handle.cmd_bind_pipeline(
|
|
||||||
*command_buffer,
|
|
||||||
vk::PipelineBindPoint::GRAPHICS,
|
|
||||||
pipeline.pipeline,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe { device.handle.cmd_draw(*command_buffer, 3, 1, 0, 0) };
|
|
||||||
|
|
||||||
unsafe { device.handle.cmd_end_render_pass(*command_buffer) };
|
|
||||||
|
|
||||||
unsafe { device.handle.end_command_buffer(*command_buffer)? };
|
|
||||||
}
|
|
||||||
|
|
||||||
let image_available_semaphore = VkSemaphore::new(device.clone())?;
|
|
||||||
let render_finished_semaphore = VkSemaphore::new(device.clone())?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
instance,
|
instance,
|
||||||
|
@ -137,35 +97,101 @@ impl VkRenderContext {
|
||||||
|
|
||||||
image_available_semaphore,
|
image_available_semaphore,
|
||||||
render_finished_semaphore,
|
render_finished_semaphore,
|
||||||
|
in_flight_fence,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&mut self) -> anyhow::Result<()> {
|
pub fn render(&mut self) -> anyhow::Result<()> {
|
||||||
let queue = self
|
unsafe { self.device.handle.wait_for_fences(&[self.in_flight_fence.handle], true, u64::MAX)? };
|
||||||
.device
|
unsafe { self.device.handle.reset_fences(&[self.in_flight_fence.handle])? };
|
||||||
.get_device_queue(0)
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Failed to get a queue"))?;
|
|
||||||
|
|
||||||
let (index, _) = self
|
let (index, _) = self
|
||||||
.swapchain
|
.swapchain
|
||||||
.acquire_next_image(&self.image_available_semaphore)?;
|
.acquire_next_image(&self.image_available_semaphore)?;
|
||||||
|
|
||||||
|
let command_buffer = self.command_buffers[index as usize];
|
||||||
|
unsafe { self.device.handle.reset_command_buffer(command_buffer, vk::CommandBufferResetFlags::default())? };
|
||||||
|
|
||||||
|
let render_area = vk::Rect2D::default().extent(self.swapchain.surface_resolution);
|
||||||
|
let clear_value = vk::ClearValue::default();
|
||||||
|
let command_buffer_begin_info = vk::CommandBufferBeginInfo::default();
|
||||||
|
unsafe {
|
||||||
|
self.device
|
||||||
|
.handle
|
||||||
|
.begin_command_buffer(command_buffer, &command_buffer_begin_info)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let clear_values = [clear_value];
|
||||||
|
let framebuffer = self.framebuffers[index as usize].as_ref();
|
||||||
|
let render_pass_begin_info = vk::RenderPassBeginInfo::default()
|
||||||
|
.render_pass(self.render_pass.handle)
|
||||||
|
.framebuffer(framebuffer.handle)
|
||||||
|
.render_area(render_area)
|
||||||
|
.clear_values(&clear_values);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.cmd_begin_render_pass(
|
||||||
|
command_buffer,
|
||||||
|
&render_pass_begin_info,
|
||||||
|
vk::SubpassContents::INLINE,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.cmd_bind_pipeline(
|
||||||
|
command_buffer,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
self.pipeline.pipeline,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let viewport = vk::Viewport::default()
|
||||||
|
.width(self.swapchain.surface_resolution.width as f32)
|
||||||
|
.height(self.swapchain.surface_resolution.height as f32)
|
||||||
|
.max_depth(1.0);
|
||||||
|
|
||||||
|
unsafe { self.device.handle.cmd_set_viewport(command_buffer, 0, &[viewport]) }
|
||||||
|
|
||||||
|
let scissor = vk::Rect2D::default().extent(self.swapchain.surface_resolution);
|
||||||
|
|
||||||
|
unsafe { self.device.handle.cmd_set_scissor(command_buffer, 0, &[scissor]) }
|
||||||
|
|
||||||
|
unsafe { self.device.handle.cmd_draw(command_buffer, 3, 1, 0, 0) };
|
||||||
|
|
||||||
|
unsafe { self.device.handle.cmd_end_render_pass(command_buffer) };
|
||||||
|
|
||||||
|
unsafe { self.device.handle.end_command_buffer(command_buffer)? };
|
||||||
|
|
||||||
let wait_semaphores = [self.image_available_semaphore.handle];
|
let wait_semaphores = [self.image_available_semaphore.handle];
|
||||||
let signal_semaphores = [self.render_finished_semaphore.handle];
|
let signal_semaphores = [self.render_finished_semaphore.handle];
|
||||||
let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
|
let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
|
||||||
let command_buffers_to_submit = [self.command_buffers[index as usize]];
|
let command_buffers_to_submit = [command_buffer];
|
||||||
let submit_info = vk::SubmitInfo::default()
|
let submit_info = vk::SubmitInfo::default()
|
||||||
.wait_semaphores(&wait_semaphores)
|
.wait_semaphores(&wait_semaphores)
|
||||||
.wait_dst_stage_mask(&wait_stages)
|
.wait_dst_stage_mask(&wait_stages)
|
||||||
.command_buffers(&command_buffers_to_submit)
|
.command_buffers(&command_buffers_to_submit)
|
||||||
.signal_semaphores(&signal_semaphores);
|
.signal_semaphores(&signal_semaphores);
|
||||||
|
|
||||||
|
let queue = self
|
||||||
|
.device
|
||||||
|
.get_device_queue(0)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Failed to get a queue"))?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.device
|
self.device
|
||||||
.handle
|
.handle
|
||||||
.queue_submit(*queue, &[submit_info], vk::Fence::null())?
|
.queue_submit(*queue, &[submit_info], self.in_flight_fence.handle)?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let swapchains = [self.swapchain.swapchain.unwrap()];
|
||||||
|
let indices = [index];
|
||||||
|
let present_info = vk::PresentInfoKHR::default()
|
||||||
|
.wait_semaphores(&signal_semaphores)
|
||||||
|
.swapchains(&swapchains)
|
||||||
|
.image_indices(&indices);
|
||||||
|
|
||||||
|
unsafe { self.device.swapchain_loader.queue_present(*queue, &present_info)? };
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ impl VkRenderPass {
|
||||||
let color_attachment = vk::AttachmentDescription::default()
|
let color_attachment = vk::AttachmentDescription::default()
|
||||||
.format(swapchain.surface_format.format)
|
.format(swapchain.surface_format.format)
|
||||||
.samples(vk::SampleCountFlags::TYPE_1)
|
.samples(vk::SampleCountFlags::TYPE_1)
|
||||||
.load_op(vk::AttachmentLoadOp::LOAD)
|
.load_op(vk::AttachmentLoadOp::CLEAR)
|
||||||
.store_op(vk::AttachmentStoreOp::STORE)
|
.store_op(vk::AttachmentStoreOp::STORE)
|
||||||
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
||||||
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
||||||
|
|
|
@ -9,13 +9,13 @@ pub struct VkSemaphore {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VkSemaphore {
|
impl VkSemaphore {
|
||||||
pub fn new(device: Arc<VkDevice>) -> anyhow::Result<Self> {
|
pub fn new(device: &Arc<VkDevice>) -> anyhow::Result<Self> {
|
||||||
let semaphore_info = vk::SemaphoreCreateInfo::default();
|
let semaphore_info = vk::SemaphoreCreateInfo::default();
|
||||||
let semaphore = unsafe { device.handle.create_semaphore(&semaphore_info, None)? };
|
let semaphore = unsafe { device.handle.create_semaphore(&semaphore_info, None)? };
|
||||||
log::debug!("Semaphore created ({semaphore:?})");
|
log::debug!("Semaphore created ({semaphore:?})");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
device,
|
device: device.clone(),
|
||||||
handle: semaphore,
|
handle: semaphore,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct VkSwapchain {
|
||||||
surface: Arc<VkSurface>,
|
surface: Arc<VkSurface>,
|
||||||
device: Arc<VkDevice>,
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
swapchain: Option<vk::SwapchainKHR>,
|
pub(super) swapchain: Option<vk::SwapchainKHR>,
|
||||||
swapchain_support_details: SwapchainSupportDetails,
|
swapchain_support_details: SwapchainSupportDetails,
|
||||||
|
|
||||||
pub(super) desired_image_count: u32,
|
pub(super) desired_image_count: u32,
|
||||||
|
@ -137,7 +137,7 @@ impl VkSwapchain {
|
||||||
&image_view,
|
&image_view,
|
||||||
&self,
|
&self,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
})
|
})
|
||||||
.map(|framebuffer| Arc::new(framebuffer))
|
.map(|framebuffer| Arc::new(framebuffer))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
|
|
Loading…
Reference in a new issue