diff options
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs')
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs | 176 |
1 files changed, 140 insertions, 36 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs index 05ce927..af20dfa 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs @@ -3,7 +3,8 @@ use ash::vk; use fparkan_platform::DepthStencilSupport; use fparkan_render::{ - LegacyBlendMode, LegacyCullMode, LegacyDepthMode, LegacyPipelineState, PipelineKey, + LegacyBlendMode, LegacyCullMode, LegacyDepthBias, LegacyDepthMode, LegacyPipelineState, + PipelineKey, }; use std::collections::BTreeMap; @@ -17,6 +18,7 @@ use super::{ }; pub(super) struct VulkanSwapchainResources { + pub(super) reflection: super::reflection::ReflectionResources, pub(super) image_views: Vec<vk::ImageView>, pub(super) images: Vec<vk::Image>, pub(super) readback_buffers: Vec<VulkanAllocatedBuffer>, @@ -145,6 +147,7 @@ pub(super) fn ensure_point_light_capacity( } struct PartialSwapchainResources { + reflection: Option<super::reflection::ReflectionResources>, image_views: Vec<vk::ImageView>, readback_buffers: Vec<VulkanAllocatedBuffer>, depth_attachments: Vec<VulkanDepthAttachment>, @@ -173,11 +176,13 @@ pub(super) fn create_swapchain_resources( device: &VulkanLogicalDeviceProbe, swapchain: &VulkanSwapchainProbe, command_pool: vk::CommandPool, + pipeline_cache: vk::PipelineCache, vertex_buffer: &VulkanAllocatedBuffer, index_buffer: &VulkanAllocatedBuffer, textures: &[VulkanAllocatedImage], texture_slot_indices: &[usize], - draw_ranges: &[super::VulkanStaticDrawRange], + base_pipeline_states: &[LegacyPipelineState], + reflection_enabled: bool, depth_request: DepthStencilSupport, reuse_command_pool: bool, ) -> Result<VulkanSwapchainResources, VulkanSmokeRendererError> { @@ -192,6 +197,7 @@ pub(super) fn create_swapchain_resources( result: error, })?; let mut partial = PartialSwapchainResources { + reflection: None, image_views: create_swapchain_image_views( device, &images, @@ -243,6 +249,18 @@ pub(super) fn create_swapchain_resources( }; partial.frame_uniform_stride = frame_uniform_stride; partial.frame_uniform_buffer = Some(frame_uniform_buffer); + partial.reflection = match super::reflection::ReflectionResources::new( + instance, + device, + command_pool, + reflection_enabled, + ) { + Ok(reflection) => Some(reflection), + Err(error) => { + destroy_partial_swapchain_resources(device, command_pool, partial); + return Err(error); + } + }; let material_count = texture_slot_indices.len() / 4; let (material_specular_buffer, material_specular_stride) = match create_material_specular_buffer(instance, device, material_count) { @@ -280,11 +298,18 @@ pub(super) fn create_swapchain_resources( ) = match create_swapchain_pipeline_bundle( instance, device, + pipeline_cache, swapchain.report.plan.format.format, swapchain.report.plan.extent, textures, texture_slot_indices, - draw_ranges, + base_pipeline_states, + partial + .reflection + .as_ref() + .expect("reflection descriptors exist") + .layout, + reflection_enabled, depth_request, partial .frame_uniform_buffer @@ -316,6 +341,24 @@ pub(super) fn create_swapchain_resources( partial.descriptor_pool = Some(descriptor_pool); partial.sampler = Some(sampler); partial.pipelines = pipelines; + if reflection_enabled { + if let Err(error) = partial + .reflection + .as_mut() + .expect("reflection descriptors exist") + .create_target( + instance, + device, + swapchain.report.plan.extent, + swapchain.report.plan.format.format, + depth_request, + render_pass, + ) + { + destroy_partial_swapchain_resources(device, command_pool, partial); + return Err(error); + } + } for _ in 1..images.len() { match create_depth_attachment( instance, @@ -391,6 +434,10 @@ pub(super) fn create_swapchain_resources( }); } Ok(VulkanSwapchainResources { + reflection: partial + .reflection + .take() + .expect("reflection descriptors exist"), image_views: partial.image_views, images, readback_buffers: partial.readback_buffers, @@ -448,11 +495,14 @@ fn create_swapchain_image_views( fn create_swapchain_pipeline_bundle( instance: &VulkanInstanceProbe, device: &VulkanLogicalDeviceProbe, + pipeline_cache: vk::PipelineCache, format: i32, extent: (u32, u32), textures: &[VulkanAllocatedImage], texture_slot_indices: &[usize], - draw_ranges: &[super::VulkanStaticDrawRange], + base_pipeline_states: &[LegacyPipelineState], + reflection_layout: vk::DescriptorSetLayout, + reflection_enabled: bool, depth_request: DepthStencilSupport, frame_uniform_buffer: &VulkanAllocatedBuffer, material_specular_buffer: &VulkanAllocatedBuffer, @@ -494,8 +544,8 @@ fn create_swapchain_pipeline_bundle( unsafe { device.device().destroy_render_pass(render_pass, None) }; destroy_depth_attachment(device, &depth_attachment); })?; - let pipeline_layout = - create_pipeline_layout(device, descriptor_set_layout).inspect_err(|_| { + let pipeline_layout = create_pipeline_layout(device, descriptor_set_layout, reflection_layout) + .inspect_err(|_| { // SAFETY: The descriptor resources and render pass were created above and are rolled back on this device. unsafe { device.device().destroy_sampler(sampler, None); @@ -509,25 +559,32 @@ fn create_swapchain_pipeline_bundle( } destroy_depth_attachment(device, &depth_attachment); })?; - let pipelines = - create_graphics_pipeline_cache(device, render_pass, pipeline_layout, extent, draw_ranges) - .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_sampler(sampler, None); - device - .device() - .destroy_descriptor_pool(descriptor_pool, None); - device - .device() - .destroy_descriptor_set_layout(descriptor_set_layout, None); - device.device().destroy_render_pass(render_pass, None); - } - destroy_depth_attachment(device, &depth_attachment); - })?; + let pipelines = create_graphics_pipeline_cache( + device, + pipeline_cache, + render_pass, + pipeline_layout, + extent, + base_pipeline_states, + reflection_enabled, + ) + .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_sampler(sampler, None); + device + .device() + .destroy_descriptor_pool(descriptor_pool, None); + device + .device() + .destroy_descriptor_set_layout(descriptor_set_layout, None); + device.device().destroy_render_pass(render_pass, None); + } + destroy_depth_attachment(device, &depth_attachment); + })?; Ok(( depth_attachment, render_pass, @@ -626,7 +683,7 @@ fn create_render_pass( .load_op(vk::AttachmentLoadOp::CLEAR) .store_op(vk::AttachmentStoreOp::STORE) .initial_layout(vk::ImageLayout::UNDEFINED) - .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); + .final_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); let color_attachment_ref = vk::AttachmentReference::default() .attachment(0) .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); @@ -651,7 +708,8 @@ fn create_render_pass( .src_subpass(vk::SUBPASS_EXTERNAL) .dst_subpass(0) .src_stage_mask( - vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT + vk::PipelineStageFlags::FRAGMENT_SHADER + | vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS, ) @@ -660,7 +718,11 @@ fn create_render_pass( | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS, ) - .src_access_mask(vk::AccessFlags::empty()) + .src_access_mask( + vk::AccessFlags::SHADER_READ + | vk::AccessFlags::COLOR_ATTACHMENT_WRITE + | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, + ) .dst_access_mask( vk::AccessFlags::COLOR_ATTACHMENT_WRITE | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, @@ -684,8 +746,9 @@ fn create_render_pass( fn create_pipeline_layout( device: &VulkanLogicalDeviceProbe, descriptor_set_layout: vk::DescriptorSetLayout, + reflection_layout: vk::DescriptorSetLayout, ) -> Result<vk::PipelineLayout, VulkanSmokeRendererError> { - let set_layouts = [descriptor_set_layout]; + let set_layouts = [descriptor_set_layout, reflection_layout]; // Material data occupies one 128-byte push-constant allocation shared by // both stages; the vertex stage also reads its specular pair from the // dynamic storage buffer at descriptor binding 5. Camera data is supplied @@ -935,25 +998,45 @@ pub(super) fn draw_viewport(extent: (u32, u32), material_mode: f32) -> vk::Viewp } } +fn depth_bias_parameters(depth_bias: LegacyDepthBias) -> (bool, f32, f32) { + match depth_bias { + LegacyDepthBias::Disabled => (false, 0.0, 0.0), + // shortcut: Vulkan constantFactor=-1.0/slopeFactor=0.0 is empirical; verify native raster state before claiming parity. + LegacyDepthBias::ProjectedDecal => (true, -1.0, 0.0), + } +} + fn create_graphics_pipeline_cache( device: &VulkanLogicalDeviceProbe, + pipeline_cache: vk::PipelineCache, render_pass: vk::RenderPass, pipeline_layout: vk::PipelineLayout, extent: (u32, u32), - draw_ranges: &[super::VulkanStaticDrawRange], + base_pipeline_states: &[LegacyPipelineState], + reflection_enabled: bool, ) -> Result<BTreeMap<PipelineKey, vk::Pipeline>, VulkanSmokeRendererError> { let mut pipelines = BTreeMap::new(); - for range in draw_ranges { - let key = range.pipeline_key(); + for state in base_pipeline_states + .iter() + .copied() + .flat_map(super::smoke::pipeline_variants) + .flat_map(|state| { + std::iter::once(state).chain( + reflection_enabled.then_some(super::reflection::reflected_pipeline_state(state)), + ) + }) + { + let key = PipelineKey::from(state); if pipelines.contains_key(&key) { continue; } let pipeline = match create_graphics_pipeline( device, + pipeline_cache, render_pass, pipeline_layout, extent, - range.pipeline_state, + state, ) { Ok(pipeline) => pipeline, Err(error) => { @@ -973,6 +1056,7 @@ fn create_graphics_pipeline_cache( fn create_graphics_pipeline( device: &VulkanLogicalDeviceProbe, + pipeline_cache: vk::PipelineCache, render_pass: vk::RenderPass, pipeline_layout: vk::PipelineLayout, extent: (u32, u32), @@ -1053,6 +1137,8 @@ fn create_graphics_pipeline( let viewport_state = vk::PipelineViewportStateCreateInfo::default() .viewports(&viewports) .scissors(&scissors); + let (depth_bias_enable, depth_bias_constant_factor, depth_bias_slope_factor) = + depth_bias_parameters(state.depth_bias); let rasterization_state = vk::PipelineRasterizationStateCreateInfo::default() .depth_clamp_enable(false) .rasterizer_discard_enable(false) @@ -1064,7 +1150,10 @@ fn create_graphics_pipeline( LegacyCullMode::FrontFace => vk::CullModeFlags::FRONT, }) .front_face(vk::FrontFace::CLOCKWISE) - .depth_bias_enable(false); + .depth_bias_enable(depth_bias_enable) + .depth_bias_constant_factor(depth_bias_constant_factor) + .depth_bias_slope_factor(depth_bias_slope_factor) + .depth_bias_clamp(0.0); let multisample_state = vk::PipelineMultisampleStateCreateInfo::default() .sample_shading_enable(false) .rasterization_samples(vk::SampleCountFlags::TYPE_1); @@ -1128,7 +1217,7 @@ fn create_graphics_pipeline( let pipeline_result = unsafe { device .device() - .create_graphics_pipelines(vk::PipelineCache::null(), &create_infos, None) + .create_graphics_pipelines(pipeline_cache, &create_infos, None) }; // SAFETY: The shader modules were created above on this live logical device and are no longer needed after pipeline creation. unsafe { @@ -1208,6 +1297,7 @@ pub(super) fn destroy_swapchain_resources( command_pool: vk::CommandPool, resources: VulkanSwapchainResources, ) { + drop(resources.reflection); // SAFETY: All handles belong to this live logical device and are destroyed during renderer teardown/recreation. unsafe { if !resources.command_buffers.is_empty() { @@ -1273,6 +1363,7 @@ fn destroy_partial_swapchain_resources( command_pool: vk::CommandPool, partial: PartialSwapchainResources, ) { + drop(partial.reflection); // SAFETY: All handles in the partial bundle belong to this live logical device and are destroyed on setup failure. unsafe { if !partial.command_buffers.is_empty() { @@ -1337,7 +1428,20 @@ fn destroy_partial_swapchain_resources( #[cfg(test)] mod tests { - use super::draw_viewport; + use super::{depth_bias_parameters, draw_viewport}; + use fparkan_render::LegacyDepthBias; + + #[test] + fn projected_decal_bias_parameters_use_empirical_vulkan_factors() { + assert_eq!( + depth_bias_parameters(LegacyDepthBias::Disabled), + (false, 0.0, 0.0) + ); + assert_eq!( + depth_bias_parameters(LegacyDepthBias::ProjectedDecal), + (true, -1.0, 0.0) + ); + } #[test] fn world_viewport_depth_keeps_distant_geometry_in_front_of_screen_sun() { |
