diff options
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi/resources.rs')
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi/resources.rs | 486 |
1 files changed, 1 insertions, 485 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/resources.rs b/adapters/fparkan-render-vulkan/src/ffi/resources.rs index 2f33faf..c6538d9 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/resources.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/resources.rs @@ -2,34 +2,13 @@ use ash::vk; -use super::{ - VulkanInstanceProbe, VulkanLogicalDeviceProbe, VulkanSmokeRendererError, VulkanSwapchainProbe, - TRIANGLE_FRAGMENT_SHADER_WORDS, TRIANGLE_VERTEX_SHADER_WORDS, -}; +use super::{VulkanInstanceProbe, VulkanLogicalDeviceProbe, VulkanSmokeRendererError}; pub(super) struct VulkanAllocatedBuffer { pub(super) buffer: vk::Buffer, pub(super) memory: vk::DeviceMemory, } -pub(super) struct VulkanSwapchainResources { - pub(super) image_views: Vec<vk::ImageView>, - pub(super) render_pass: vk::RenderPass, - pub(super) pipeline_layout: vk::PipelineLayout, - pub(super) pipeline: vk::Pipeline, - pub(super) framebuffers: Vec<vk::Framebuffer>, - pub(super) command_buffers: Vec<vk::CommandBuffer>, -} - -struct PartialSwapchainResources { - image_views: Vec<vk::ImageView>, - render_pass: Option<vk::RenderPass>, - pipeline_layout: Option<vk::PipelineLayout>, - pipeline: Option<vk::Pipeline>, - framebuffers: Vec<vk::Framebuffer>, - command_buffers: Vec<vk::CommandBuffer>, -} - pub(super) struct VulkanFrameSync { pub(super) image_available: vk::Semaphore, pub(super) render_finished: vk::Semaphore, @@ -197,411 +176,6 @@ fn find_memory_type( }) } -pub(super) fn create_swapchain_resources( - device: &VulkanLogicalDeviceProbe, - swapchain: &VulkanSwapchainProbe, - command_pool: vk::CommandPool, - vertex_buffer: &VulkanAllocatedBuffer, - index_buffer: &VulkanAllocatedBuffer, - reuse_command_pool: bool, -) -> Result<VulkanSwapchainResources, VulkanSmokeRendererError> { - // SAFETY: The swapchain is live and owned by this renderer for the duration of the query. - let images = unsafe { - swapchain - .loader() - .get_swapchain_images(swapchain.swapchain()) - } - .map_err(|error| VulkanSmokeRendererError::VulkanOperation { - context: "vkGetSwapchainImagesKHR", - result: error, - })?; - let mut partial = PartialSwapchainResources { - image_views: create_swapchain_image_views( - device, - &images, - swapchain.report.plan.format.format, - )?, - render_pass: None, - pipeline_layout: None, - pipeline: None, - framebuffers: Vec::new(), - command_buffers: Vec::new(), - }; - let (render_pass, pipeline_layout, pipeline) = match create_swapchain_pipeline_bundle( - device, - swapchain.report.plan.format.format, - swapchain.report.plan.extent, - ) { - Ok(bundle) => bundle, - Err(error) => { - destroy_partial_swapchain_resources(device, command_pool, partial); - return Err(error); - } - }; - partial.render_pass = Some(render_pass); - partial.pipeline_layout = Some(pipeline_layout); - partial.pipeline = Some(pipeline); - let framebuffers = match create_swapchain_framebuffers( - device, - render_pass, - &partial.image_views, - swapchain.report.plan.extent, - ) { - Ok(framebuffers) => framebuffers, - Err(error) => { - destroy_partial_swapchain_resources(device, command_pool, partial); - return Err(error); - } - }; - partial.framebuffers = framebuffers; - reset_reusable_command_pool(device, command_pool, reuse_command_pool)?; - let command_buffers = match allocate_command_buffers( - device, - command_pool, - u32::try_from(images.len()).unwrap_or(u32::MAX), - ) { - Ok(command_buffers) => command_buffers, - Err(error) => { - destroy_partial_swapchain_resources(device, command_pool, partial); - return Err(error); - } - }; - partial.command_buffers = command_buffers; - let _ = (vertex_buffer, index_buffer); - Ok(VulkanSwapchainResources { - image_views: partial.image_views, - render_pass, - pipeline_layout, - pipeline, - framebuffers: partial.framebuffers, - command_buffers: partial.command_buffers, - }) -} - -fn create_swapchain_image_views( - device: &VulkanLogicalDeviceProbe, - images: &[vk::Image], - format: i32, -) -> Result<Vec<vk::ImageView>, VulkanSmokeRendererError> { - let mut image_views = Vec::with_capacity(images.len()); - for image in images.iter().copied() { - image_views.push(create_image_view(device, image, format)?); - } - Ok(image_views) -} - -fn create_swapchain_pipeline_bundle( - device: &VulkanLogicalDeviceProbe, - format: i32, - extent: (u32, u32), -) -> Result<(vk::RenderPass, vk::PipelineLayout, vk::Pipeline), VulkanSmokeRendererError> { - let render_pass = create_render_pass(device, format)?; - let pipeline_layout = create_pipeline_layout(device).inspect_err(|_| { - // SAFETY: The render pass was created above on this live logical device and is destroyed on setup failure. - unsafe { device.device().destroy_render_pass(render_pass, None) }; - })?; - let pipeline = create_graphics_pipeline(device, render_pass, pipeline_layout, extent) - .inspect_err(|_| { - // SAFETY: These objects were created above on this live logical device and are destroyed on setup failure. - unsafe { - device - .device() - .destroy_pipeline_layout(pipeline_layout, None); - device.device().destroy_render_pass(render_pass, None); - } - })?; - Ok((render_pass, pipeline_layout, pipeline)) -} - -fn create_swapchain_framebuffers( - device: &VulkanLogicalDeviceProbe, - render_pass: vk::RenderPass, - image_views: &[vk::ImageView], - extent: (u32, u32), -) -> Result<Vec<vk::Framebuffer>, VulkanSmokeRendererError> { - let mut framebuffers = Vec::with_capacity(image_views.len()); - for image_view in image_views.iter().copied() { - match create_framebuffer(device, render_pass, image_view, extent) { - Ok(framebuffer) => framebuffers.push(framebuffer), - Err(error) => { - // SAFETY: These framebuffers were created above on this live logical device and are destroyed on setup failure. - unsafe { - for framebuffer in framebuffers.iter().copied() { - device.device().destroy_framebuffer(framebuffer, None); - } - } - return Err(error); - } - } - } - Ok(framebuffers) -} - -fn reset_reusable_command_pool( - device: &VulkanLogicalDeviceProbe, - command_pool: vk::CommandPool, - reuse_command_pool: bool, -) -> Result<(), VulkanSmokeRendererError> { - if !reuse_command_pool { - return Ok(()); - } - // SAFETY: All command buffers allocated from the live pool are freed before reallocating them. - unsafe { - device - .device() - .reset_command_pool(command_pool, vk::CommandPoolResetFlags::empty()) - } - .map_err(|error| VulkanSmokeRendererError::VulkanOperation { - context: "vkResetCommandPool", - result: error, - }) -} - -fn create_image_view( - device: &VulkanLogicalDeviceProbe, - image: vk::Image, - format: i32, -) -> Result<vk::ImageView, VulkanSmokeRendererError> { - let create_info = vk::ImageViewCreateInfo::default() - .image(image) - .view_type(vk::ImageViewType::TYPE_2D) - .format(vk::Format::from_raw(format)) - .subresource_range(color_subresource_range()); - // SAFETY: The image comes from the live swapchain and the subresource range covers its color aspect. - unsafe { device.device().create_image_view(&create_info, None) }.map_err(|error| { - VulkanSmokeRendererError::VulkanOperation { - context: "vkCreateImageView", - result: error, - } - }) -} - -fn create_render_pass( - device: &VulkanLogicalDeviceProbe, - format: i32, -) -> Result<vk::RenderPass, VulkanSmokeRendererError> { - let color_attachment = vk::AttachmentDescription::default() - .format(vk::Format::from_raw(format)) - .samples(vk::SampleCountFlags::TYPE_1) - .load_op(vk::AttachmentLoadOp::CLEAR) - .store_op(vk::AttachmentStoreOp::STORE) - .initial_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .final_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); - 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 dependency = vk::SubpassDependency::default() - .src_subpass(vk::SUBPASS_EXTERNAL) - .dst_subpass(0) - .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) - .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) - .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); - let attachments = [color_attachment]; - let subpasses = [subpass]; - let dependencies = [dependency]; - let create_info = vk::RenderPassCreateInfo::default() - .attachments(&attachments) - .subpasses(&subpasses) - .dependencies(&dependencies); - // SAFETY: The render-pass create info only references stack-owned descriptors. - unsafe { device.device().create_render_pass(&create_info, None) }.map_err(|error| { - VulkanSmokeRendererError::VulkanOperation { - context: "vkCreateRenderPass", - result: error, - } - }) -} - -fn create_pipeline_layout( - device: &VulkanLogicalDeviceProbe, -) -> Result<vk::PipelineLayout, VulkanSmokeRendererError> { - let create_info = vk::PipelineLayoutCreateInfo::default(); - // SAFETY: The pipeline layout contains no descriptor sets or push constants. - unsafe { device.device().create_pipeline_layout(&create_info, None) }.map_err(|error| { - VulkanSmokeRendererError::VulkanOperation { - context: "vkCreatePipelineLayout", - result: error, - } - }) -} - -fn extent_component_to_f32(value: u32) -> f32 { - u16::try_from(value).map_or(f32::from(u16::MAX), f32::from) -} - -#[allow(clippy::too_many_lines)] -fn create_graphics_pipeline( - device: &VulkanLogicalDeviceProbe, - render_pass: vk::RenderPass, - pipeline_layout: vk::PipelineLayout, - extent: (u32, u32), -) -> Result<vk::Pipeline, VulkanSmokeRendererError> { - let entry_point = c"main"; - let vertex_module = create_shader_module(device, TRIANGLE_VERTEX_SHADER_WORDS)?; - let fragment_module = match create_shader_module(device, TRIANGLE_FRAGMENT_SHADER_WORDS) { - Ok(fragment_module) => fragment_module, - Err(error) => { - // SAFETY: The vertex shader module was created above on this logical device and is destroyed on setup failure. - unsafe { device.device().destroy_shader_module(vertex_module, None) }; - return Err(error); - } - }; - let stage_create_infos = [ - vk::PipelineShaderStageCreateInfo::default() - .stage(vk::ShaderStageFlags::VERTEX) - .module(vertex_module) - .name(entry_point), - vk::PipelineShaderStageCreateInfo::default() - .stage(vk::ShaderStageFlags::FRAGMENT) - .module(fragment_module) - .name(entry_point), - ]; - let binding_descriptions = [vk::VertexInputBindingDescription { - binding: 0, - stride: 20, - input_rate: vk::VertexInputRate::VERTEX, - }]; - let attribute_descriptions = [ - vk::VertexInputAttributeDescription { - location: 0, - binding: 0, - format: vk::Format::R32G32_SFLOAT, - offset: 0, - }, - vk::VertexInputAttributeDescription { - location: 1, - binding: 0, - format: vk::Format::R32G32B32_SFLOAT, - offset: 8, - }, - ]; - let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::default() - .vertex_binding_descriptions(&binding_descriptions) - .vertex_attribute_descriptions(&attribute_descriptions); - let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::default() - .topology(vk::PrimitiveTopology::TRIANGLE_LIST); - let viewports = [vk::Viewport { - x: 0.0, - y: 0.0, - width: extent_component_to_f32(extent.0), - height: extent_component_to_f32(extent.1), - min_depth: 0.0, - max_depth: 1.0, - }]; - let scissors = [vk::Rect2D { - offset: vk::Offset2D { x: 0, y: 0 }, - extent: vk::Extent2D { - width: extent.0, - height: extent.1, - }, - }]; - let viewport_state = vk::PipelineViewportStateCreateInfo::default() - .viewports(&viewports) - .scissors(&scissors); - let rasterization_state = vk::PipelineRasterizationStateCreateInfo::default() - .polygon_mode(vk::PolygonMode::FILL) - .cull_mode(vk::CullModeFlags::BACK) - .front_face(vk::FrontFace::CLOCKWISE) - .line_width(1.0); - let multisample_state = vk::PipelineMultisampleStateCreateInfo::default() - .rasterization_samples(vk::SampleCountFlags::TYPE_1); - let color_blend_attachment = [vk::PipelineColorBlendAttachmentState::default() - .color_write_mask( - vk::ColorComponentFlags::R - | vk::ColorComponentFlags::G - | vk::ColorComponentFlags::B - | vk::ColorComponentFlags::A, - )]; - let color_blend_state = - vk::PipelineColorBlendStateCreateInfo::default().attachments(&color_blend_attachment); - let create_info = [vk::GraphicsPipelineCreateInfo::default() - .stages(&stage_create_infos) - .vertex_input_state(&vertex_input_state) - .input_assembly_state(&input_assembly_state) - .viewport_state(&viewport_state) - .rasterization_state(&rasterization_state) - .multisample_state(&multisample_state) - .color_blend_state(&color_blend_state) - .layout(pipeline_layout) - .render_pass(render_pass) - .subpass(0)]; - // SAFETY: The pipeline creation references live shader modules and stack-owned fixed-function descriptors. - let pipeline_result = unsafe { - device - .device() - .create_graphics_pipelines(vk::PipelineCache::null(), &create_info, None) - }; - // SAFETY: Shader modules are no longer needed after pipeline creation completes. - unsafe { - device.device().destroy_shader_module(vertex_module, None); - device.device().destroy_shader_module(fragment_module, None); - } - let pipeline = - pipeline_result.map_err(|(_, error)| VulkanSmokeRendererError::VulkanOperation { - context: "vkCreateGraphicsPipelines", - result: error, - })?[0]; - Ok(pipeline) -} - -fn create_shader_module( - device: &VulkanLogicalDeviceProbe, - words: &[u32], -) -> Result<vk::ShaderModule, VulkanSmokeRendererError> { - let create_info = vk::ShaderModuleCreateInfo::default().code(words); - // SAFETY: SPIR-V words are immutable and valid for the duration of the call. - unsafe { device.device().create_shader_module(&create_info, None) }.map_err(|error| { - VulkanSmokeRendererError::VulkanOperation { - context: "vkCreateShaderModule", - result: error, - } - }) -} - -fn create_framebuffer( - device: &VulkanLogicalDeviceProbe, - render_pass: vk::RenderPass, - image_view: vk::ImageView, - extent: (u32, u32), -) -> Result<vk::Framebuffer, VulkanSmokeRendererError> { - let attachments = [image_view]; - let create_info = vk::FramebufferCreateInfo::default() - .render_pass(render_pass) - .attachments(&attachments) - .width(extent.0) - .height(extent.1) - .layers(1); - // SAFETY: The framebuffer attachments and render pass remain live for the duration of the call. - unsafe { device.device().create_framebuffer(&create_info, None) }.map_err(|error| { - VulkanSmokeRendererError::VulkanOperation { - context: "vkCreateFramebuffer", - result: error, - } - }) -} - -fn allocate_command_buffers( - device: &VulkanLogicalDeviceProbe, - command_pool: vk::CommandPool, - count: u32, -) -> Result<Vec<vk::CommandBuffer>, VulkanSmokeRendererError> { - let allocate_info = vk::CommandBufferAllocateInfo::default() - .command_pool(command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(count); - // SAFETY: Command buffers are allocated from a live resettable pool owned by this device. - unsafe { device.device().allocate_command_buffers(&allocate_info) }.map_err(|error| { - VulkanSmokeRendererError::VulkanOperation { - context: "vkAllocateCommandBuffers", - result: error, - } - }) -} - pub(super) fn create_frame_sync( device: &VulkanLogicalDeviceProbe, ) -> Result<Vec<VulkanFrameSync>, VulkanSmokeRendererError> { @@ -655,64 +229,6 @@ pub(super) fn create_frame_sync( Ok(sync) } -pub(super) fn destroy_swapchain_resources( - device: &VulkanLogicalDeviceProbe, - command_pool: vk::CommandPool, - resources: VulkanSwapchainResources, -) { - // SAFETY: All swapchain-dependent objects belong to this device and are destroyed once. - unsafe { - device - .device() - .free_command_buffers(command_pool, &resources.command_buffers); - for framebuffer in resources.framebuffers { - device.device().destroy_framebuffer(framebuffer, None); - } - device.device().destroy_pipeline(resources.pipeline, None); - device - .device() - .destroy_pipeline_layout(resources.pipeline_layout, None); - device - .device() - .destroy_render_pass(resources.render_pass, None); - for image_view in resources.image_views { - device.device().destroy_image_view(image_view, None); - } - } -} - -fn destroy_partial_swapchain_resources( - device: &VulkanLogicalDeviceProbe, - command_pool: vk::CommandPool, - resources: PartialSwapchainResources, -) { - // SAFETY: All handles in this partial resource set were created on this live logical device and are destroyed once. - unsafe { - if !resources.command_buffers.is_empty() { - device - .device() - .free_command_buffers(command_pool, &resources.command_buffers); - } - for framebuffer in resources.framebuffers { - device.device().destroy_framebuffer(framebuffer, None); - } - if let Some(pipeline) = resources.pipeline { - device.device().destroy_pipeline(pipeline, None); - } - if let Some(pipeline_layout) = resources.pipeline_layout { - device - .device() - .destroy_pipeline_layout(pipeline_layout, None); - } - if let Some(render_pass) = resources.render_pass { - device.device().destroy_render_pass(render_pass, None); - } - for image_view in resources.image_views { - device.device().destroy_image_view(image_view, None); - } - } -} - fn destroy_frame_sync_objects(device: &VulkanLogicalDeviceProbe, sync: &[VulkanFrameSync]) { for frame_sync in sync { // SAFETY: These sync objects belong to this live logical device and are destroyed once during teardown. |
