This commit is contained in:
parent
f67804abd9
commit
504fdada42
5 changed files with 245 additions and 63 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
pub(self) mod vk_render_context;
|
pub(self) mod vk_render_context;
|
||||||
pub use vk_render_context::VkRenderContext;
|
pub use vk_render_context::VkRenderContext;
|
||||||
|
|
||||||
|
@ -16,5 +18,12 @@ pub use vk_device::VkDevice;
|
||||||
pub(self) mod vk_swapchain;
|
pub(self) mod vk_swapchain;
|
||||||
pub use vk_swapchain::VkSwapchain;
|
pub use vk_swapchain::VkSwapchain;
|
||||||
|
|
||||||
|
pub(self) mod vk_shader_module;
|
||||||
|
pub use vk_shader_module::VkShaderModule;
|
||||||
|
|
||||||
|
pub(self) mod vk_graphics_pipeline;
|
||||||
|
pub use vk_graphics_pipeline::VkGraphicsPipeline;
|
||||||
|
|
||||||
|
mod vk_render_pass;
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
mod vk_shader_module;
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ pub struct VkDevice {
|
||||||
instance: Arc<VkInstance>,
|
instance: Arc<VkInstance>,
|
||||||
pub(super) handle: ash::Device,
|
pub(super) handle: ash::Device,
|
||||||
pub(super) swapchain_loader: ash::khr::swapchain::Device,
|
pub(super) swapchain_loader: ash::khr::swapchain::Device,
|
||||||
|
pub(super) queue_family_index: u32,
|
||||||
queue_family_index: u32,
|
|
||||||
|
|
||||||
// Arc not used because vk::Queue is destroyed with Device automatically
|
// Arc not used because vk::Queue is destroyed with Device automatically
|
||||||
// so any references of vk::Queue must be destroyed with VkDevice
|
// so any references of vk::Queue must be destroyed with VkDevice
|
||||||
|
|
131
src/vulkan/vk_graphics_pipeline.rs
Normal file
131
src/vulkan/vk_graphics_pipeline.rs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
use crate::vulkan::vk_render_pass::VkRenderPass;
|
||||||
|
use crate::vulkan::{VkDevice, VkShaderModule, VkSwapchain};
|
||||||
|
use ash::vk;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkGraphicsPipeline {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
swapchain: Arc<VkSwapchain>,
|
||||||
|
render_pass: Arc<VkRenderPass>,
|
||||||
|
|
||||||
|
pipeline_layout: vk::PipelineLayout,
|
||||||
|
pipeline: vk::Pipeline,
|
||||||
|
vertex_shader: VkShaderModule,
|
||||||
|
fragment_shader: VkShaderModule,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkGraphicsPipeline {
|
||||||
|
pub fn new(
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
swapchain: Arc<VkSwapchain>,
|
||||||
|
render_pass: Arc<VkRenderPass>,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let shader_entry_name = CStr::from_bytes_with_nul(b"main\0")?;
|
||||||
|
|
||||||
|
let vert_shader_module =
|
||||||
|
VkShaderModule::from_spv_file(device.clone(), "res/shaders/main.vert.spv")?;
|
||||||
|
|
||||||
|
let vert_shader_info = vk::PipelineShaderStageCreateInfo::default()
|
||||||
|
.module(vert_shader_module.handle)
|
||||||
|
.name(shader_entry_name)
|
||||||
|
.stage(vk::ShaderStageFlags::VERTEX);
|
||||||
|
|
||||||
|
let frag_shader_module =
|
||||||
|
VkShaderModule::from_spv_file(device.clone(), "res/shaders/main.frag.spv")?;
|
||||||
|
|
||||||
|
let frag_shader_info = vk::PipelineShaderStageCreateInfo::default()
|
||||||
|
.module(frag_shader_module.handle)
|
||||||
|
.name(shader_entry_name)
|
||||||
|
.stage(vk::ShaderStageFlags::FRAGMENT);
|
||||||
|
|
||||||
|
let shader_stage_create_infos = [vert_shader_info, frag_shader_info];
|
||||||
|
|
||||||
|
let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default();
|
||||||
|
|
||||||
|
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
||||||
|
.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()
|
||||||
|
.viewports(&viewports)
|
||||||
|
.scissors(&scissors);
|
||||||
|
|
||||||
|
let rasterizer = vk::PipelineRasterizationStateCreateInfo::default()
|
||||||
|
.polygon_mode(vk::PolygonMode::FILL)
|
||||||
|
.cull_mode(vk::CullModeFlags::BACK)
|
||||||
|
.front_face(vk::FrontFace::CLOCKWISE)
|
||||||
|
.line_width(1.0);
|
||||||
|
|
||||||
|
let multisampling = vk::PipelineMultisampleStateCreateInfo::default()
|
||||||
|
.rasterization_samples(vk::SampleCountFlags::TYPE_1)
|
||||||
|
.min_sample_shading(1.0);
|
||||||
|
|
||||||
|
let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default()
|
||||||
|
.color_write_mask(vk::ColorComponentFlags::RGBA);
|
||||||
|
|
||||||
|
let attachments = [color_blend_attachment];
|
||||||
|
let color_blending =
|
||||||
|
vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments);
|
||||||
|
|
||||||
|
let dynamic_state = vk::PipelineDynamicStateCreateInfo::default()
|
||||||
|
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::LINE_WIDTH]);
|
||||||
|
|
||||||
|
let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default();
|
||||||
|
let pipeline_layout = unsafe {
|
||||||
|
device
|
||||||
|
.handle
|
||||||
|
.create_pipeline_layout(&pipeline_layout_info, None)?
|
||||||
|
};
|
||||||
|
log::debug!("Pipeline layout created ({pipeline_layout:?})");
|
||||||
|
|
||||||
|
let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
|
||||||
|
.stages(&shader_stage_create_infos)
|
||||||
|
.vertex_input_state(&vertex_input_info)
|
||||||
|
.input_assembly_state(&input_assembly)
|
||||||
|
.viewport_state(&viewport_state)
|
||||||
|
.rasterization_state(&rasterizer)
|
||||||
|
.multisample_state(&multisampling)
|
||||||
|
.color_blend_state(&color_blending)
|
||||||
|
.dynamic_state(&dynamic_state)
|
||||||
|
.layout(pipeline_layout)
|
||||||
|
.render_pass(render_pass.handle);
|
||||||
|
let pipeline = unsafe {
|
||||||
|
device
|
||||||
|
.handle
|
||||||
|
.create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None)
|
||||||
|
.map_err(|(_, error)| error)?[0]
|
||||||
|
};
|
||||||
|
log::debug!("Pipeline created ({pipeline_layout:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device,
|
||||||
|
swapchain,
|
||||||
|
render_pass,
|
||||||
|
pipeline_layout,
|
||||||
|
pipeline,
|
||||||
|
vertex_shader: vert_shader_module,
|
||||||
|
fragment_shader: frag_shader_module,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkGraphicsPipeline {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.destroy_pipeline(self.pipeline, None);
|
||||||
|
log::debug!("Pipeline destroyed ({:?})", self.pipeline);
|
||||||
|
|
||||||
|
self.device.handle.destroy_pipeline_layout(self.pipeline_layout, None);
|
||||||
|
log::debug!("Pipeline layout destroyed ({:?})", self.pipeline_layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::vulkan::vk_shader_module::VkShaderModule;
|
use crate::vulkan::vk_render_pass::VkRenderPass;
|
||||||
use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface, VkSwapchain};
|
use crate::vulkan::{VkDevice, VkGraphicsPipeline, VkInstance, VkPhysicalDevice, VkSurface, VkSwapchain};
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
use ash::vk::PrimitiveTopology;
|
|
||||||
use std::ffi::{CStr, CString};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct VkRenderContext {
|
pub struct VkRenderContext {
|
||||||
|
@ -29,7 +27,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()
|
||||||
|
@ -48,69 +46,51 @@ impl VkRenderContext {
|
||||||
&physical_device,
|
&physical_device,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
let shader_entry_name = CStr::from_bytes_with_nul(b"main\0")?;
|
let render_pass = Arc::new(VkRenderPass::new(
|
||||||
|
device.clone(),
|
||||||
|
swapchain.clone(),
|
||||||
|
)?);
|
||||||
|
|
||||||
let vert_shader_module =
|
let pipeline = Arc::new(VkGraphicsPipeline::new(
|
||||||
VkShaderModule::from_spv_file(device.clone(), "res/shaders/main.vert.spv")?;
|
device.clone(),
|
||||||
|
swapchain.clone(),
|
||||||
|
render_pass.clone(),
|
||||||
|
)?);
|
||||||
|
|
||||||
let vert_shader_info = vk::PipelineShaderStageCreateInfo::default()
|
let framebuffers = swapchain.present_image_views
|
||||||
.module(vert_shader_module.handle)
|
.as_ref()
|
||||||
.name(shader_entry_name)
|
.ok_or_else(|| anyhow::anyhow!("No present image views found"))?
|
||||||
.stage(vk::ShaderStageFlags::VERTEX);
|
.iter()
|
||||||
|
.map(|present_image_view| {
|
||||||
|
let attachments = [*present_image_view];
|
||||||
|
let framebuffer_info = vk::FramebufferCreateInfo::default()
|
||||||
|
.render_pass(render_pass.handle)
|
||||||
|
.width(swapchain.surface_resolution.width)
|
||||||
|
.height(swapchain.surface_resolution.height)
|
||||||
|
.attachments(&attachments)
|
||||||
|
.layers(1);
|
||||||
|
|
||||||
let frag_shader_module =
|
unsafe { device.handle.create_framebuffer(&framebuffer_info, None).unwrap() }
|
||||||
VkShaderModule::from_spv_file(device.clone(), "res/shaders/main.frag.spv")?;
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let frag_shader_info = vk::PipelineShaderStageCreateInfo::default()
|
let command_pool_info = vk::CommandPoolCreateInfo::default()
|
||||||
.module(frag_shader_module.handle)
|
.queue_family_index(device.queue_family_index);
|
||||||
.name(shader_entry_name)
|
let command_pool = unsafe { device.handle.create_command_pool(&command_pool_info, None)? };
|
||||||
.stage(vk::ShaderStageFlags::FRAGMENT);
|
|
||||||
|
|
||||||
let shader_stage_create_infos = [vert_shader_info, frag_shader_info];
|
let command_buffer_info = vk::CommandBufferAllocateInfo::default()
|
||||||
|
.command_pool(command_pool)
|
||||||
|
.level(vk::CommandBufferLevel::PRIMARY)
|
||||||
|
.command_buffer_count(framebuffers.len() as u32);
|
||||||
|
|
||||||
let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default();
|
// Destroyed with command pool
|
||||||
|
let command_buffers = unsafe { device.handle.allocate_command_buffers(&command_buffer_info)? };
|
||||||
|
|
||||||
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
|
||||||
.topology(PrimitiveTopology::TRIANGLE_LIST);
|
|
||||||
|
|
||||||
let viewport = vk::Viewport::default()
|
unsafe { device.handle.destroy_command_pool(command_pool, None) };
|
||||||
.width(swapchain.surface_resolution.width as f32)
|
for framebuffer in framebuffers {
|
||||||
.height(swapchain.surface_resolution.height as f32)
|
unsafe { device.handle.destroy_framebuffer(framebuffer, None) };
|
||||||
.max_depth(1.0);
|
}
|
||||||
|
|
||||||
let scissor = vk::Rect2D::default().extent(swapchain.surface_resolution);
|
|
||||||
|
|
||||||
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
|
||||||
.viewports(&[viewport])
|
|
||||||
.scissors(&[scissor]);
|
|
||||||
|
|
||||||
let rasterizer = vk::PipelineRasterizationStateCreateInfo::default()
|
|
||||||
.polygon_mode(vk::PolygonMode::FILL)
|
|
||||||
.cull_mode(vk::CullModeFlags::BACK)
|
|
||||||
.front_face(vk::FrontFace::CLOCKWISE)
|
|
||||||
.line_width(1.0);
|
|
||||||
|
|
||||||
let multisampling = vk::PipelineMultisampleStateCreateInfo::default()
|
|
||||||
.rasterization_samples(vk::SampleCountFlags::TYPE_1)
|
|
||||||
.min_sample_shading(1.0);
|
|
||||||
|
|
||||||
let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default()
|
|
||||||
.color_write_mask(vk::ColorComponentFlags::RGBA);
|
|
||||||
|
|
||||||
let color_blending =
|
|
||||||
vk::PipelineColorBlendStateCreateInfo::default().attachments(&[color_blend_attachment]);
|
|
||||||
|
|
||||||
let dynamic_state = vk::PipelineDynamicStateCreateInfo::default()
|
|
||||||
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::LINE_WIDTH]);
|
|
||||||
|
|
||||||
let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default();
|
|
||||||
let pipeline_layout = unsafe {
|
|
||||||
device
|
|
||||||
.handle
|
|
||||||
.create_pipeline_layout(&pipeline_layout_info, None)?
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe { device.handle.destroy_pipeline_layout(pipeline_layout, None) };
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
instance,
|
instance,
|
||||||
|
|
63
src/vulkan/vk_render_pass.rs
Normal file
63
src/vulkan/vk_render_pass.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use crate::vulkan::{VkDevice, VkSwapchain};
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkRenderPass {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
swapchain: Arc<VkSwapchain>,
|
||||||
|
|
||||||
|
pub(super) handle: vk::RenderPass,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkRenderPass {
|
||||||
|
pub fn new(
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
swapchain: Arc<VkSwapchain>,
|
||||||
|
) -> VkResult<Self> {
|
||||||
|
let color_attachment = vk::AttachmentDescription::default()
|
||||||
|
.format(swapchain.surface_format.format)
|
||||||
|
.samples(vk::SampleCountFlags::TYPE_1)
|
||||||
|
.load_op(vk::AttachmentLoadOp::LOAD)
|
||||||
|
.store_op(vk::AttachmentStoreOp::STORE)
|
||||||
|
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
||||||
|
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
||||||
|
.initial_layout(vk::ImageLayout::UNDEFINED)
|
||||||
|
.final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
|
||||||
|
|
||||||
|
let color_attachment_ref = vk::AttachmentReference::default()
|
||||||
|
.attachment(0)
|
||||||
|
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
let color_attachments = [color_attachment_ref];
|
||||||
|
let subpass = vk::SubpassDescription::default()
|
||||||
|
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
||||||
|
.color_attachments(&color_attachments);
|
||||||
|
|
||||||
|
let attachments = [color_attachment];
|
||||||
|
let subpasses = [subpass];
|
||||||
|
let render_pass_info = vk::RenderPassCreateInfo::default()
|
||||||
|
.attachments(&attachments)
|
||||||
|
.subpasses(&subpasses);
|
||||||
|
|
||||||
|
let render_pass = unsafe {
|
||||||
|
device.handle.create_render_pass(&render_pass_info, None)?
|
||||||
|
};
|
||||||
|
log::debug!("Render pass created ({render_pass:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device,
|
||||||
|
swapchain,
|
||||||
|
handle: render_pass,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkRenderPass {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.destroy_render_pass(self.handle, None);
|
||||||
|
log::debug!("Render pass destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue