diff options
| author | Valentin Popov <valentin@popov.link> | 2026-07-18 07:07:45 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-07-18 07:07:45 +0300 |
| commit | efaba9001fb64eca14db3668c1c5295f078691b5 (patch) | |
| tree | 867a465547d992bbb4b048cc438f6e97d9398b2d /adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs | |
| parent | b915554f3c5695bd8b9707359ffaa51ea8742341 (diff) | |
| download | fparkan-efaba9001fb64eca14db3668c1c5295f078691b5.tar.xz fparkan-efaba9001fb64eca14db3668c1c5295f078691b5.zip | |
feat(render): bind materials per mesh batch
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs')
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs index 50bf0a1..8dbbc27 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs @@ -14,7 +14,7 @@ pub(super) struct VulkanSwapchainResources { pub(super) pipeline_layout: vk::PipelineLayout, pub(super) descriptor_set_layout: vk::DescriptorSetLayout, pub(super) descriptor_pool: vk::DescriptorPool, - pub(super) descriptor_set: vk::DescriptorSet, + pub(super) descriptor_sets: Vec<vk::DescriptorSet>, pub(super) sampler: vk::Sampler, pub(super) pipeline: vk::Pipeline, pub(super) framebuffers: Vec<vk::Framebuffer>, @@ -39,7 +39,7 @@ pub(super) fn create_swapchain_resources( command_pool: vk::CommandPool, vertex_buffer: &VulkanAllocatedBuffer, index_buffer: &VulkanAllocatedBuffer, - texture: &VulkanAllocatedImage, + textures: &[VulkanAllocatedImage], reuse_command_pool: bool, ) -> Result<VulkanSwapchainResources, VulkanSmokeRendererError> { // SAFETY: The swapchain is live and owned by this renderer for the duration of the query. @@ -73,13 +73,13 @@ pub(super) fn create_swapchain_resources( pipeline, descriptor_set_layout, descriptor_pool, - descriptor_set, + descriptor_sets, sampler, ) = match create_swapchain_pipeline_bundle( device, swapchain.report.plan.format.format, swapchain.report.plan.extent, - texture, + textures, ) { Ok(bundle) => bundle, Err(error) => { @@ -126,7 +126,7 @@ pub(super) fn create_swapchain_resources( pipeline_layout, descriptor_set_layout, descriptor_pool, - descriptor_set, + descriptor_sets, sampler, pipeline, framebuffers: partial.framebuffers, @@ -151,7 +151,7 @@ fn create_swapchain_pipeline_bundle( device: &VulkanLogicalDeviceProbe, format: i32, extent: (u32, u32), - texture: &VulkanAllocatedImage, + textures: &[VulkanAllocatedImage], ) -> Result< ( vk::RenderPass, @@ -159,14 +159,14 @@ fn create_swapchain_pipeline_bundle( vk::Pipeline, vk::DescriptorSetLayout, vk::DescriptorPool, - vk::DescriptorSet, + Vec<vk::DescriptorSet>, vk::Sampler, ), VulkanSmokeRendererError, > { let render_pass = create_render_pass(device, format)?; - let (descriptor_set_layout, descriptor_pool, descriptor_set, sampler) = - create_texture_descriptor_bundle(device, texture).inspect_err(|_| { + let (descriptor_set_layout, descriptor_pool, descriptor_sets, sampler) = + create_texture_descriptor_bundle(device, textures).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) }; })?; @@ -207,7 +207,7 @@ fn create_swapchain_pipeline_bundle( pipeline, descriptor_set_layout, descriptor_pool, - descriptor_set, + descriptor_sets, sampler, )) } @@ -334,12 +334,12 @@ fn create_pipeline_layout( #[allow(clippy::too_many_lines)] fn create_texture_descriptor_bundle( device: &VulkanLogicalDeviceProbe, - texture: &VulkanAllocatedImage, + textures: &[VulkanAllocatedImage], ) -> Result< ( vk::DescriptorSetLayout, vk::DescriptorPool, - vk::DescriptorSet, + Vec<vk::DescriptorSet>, vk::Sampler, ), VulkanSmokeRendererError, @@ -361,13 +361,23 @@ fn create_texture_descriptor_bundle( context: "vkCreateDescriptorSetLayout", result, })?; + let texture_count = u32::try_from(textures.len()).map_err(|_| { + VulkanSmokeRendererError::InvariantViolation { + context: "static material texture count exceeds Vulkan descriptor limit", + } + })?; + if texture_count == 0 { + return Err(VulkanSmokeRendererError::InvariantViolation { + context: "static material texture list is empty", + }); + } let pool_size = vk::DescriptorPoolSize::default() .ty(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) - .descriptor_count(1); + .descriptor_count(texture_count); let pool_sizes = [pool_size]; let pool_info = vk::DescriptorPoolCreateInfo::default() .pool_sizes(&pool_sizes) - .max_sets(1); + .max_sets(texture_count); let pool = // SAFETY: The pool description is stack-owned and reserves exactly one descriptor. unsafe { device.device().create_descriptor_pool(&pool_info, None) }.map_err(|result| { @@ -378,12 +388,12 @@ fn create_texture_descriptor_bundle( result, } })?; - let layouts = [layout]; + let layouts = vec![layout; textures.len()]; let allocate_info = vk::DescriptorSetAllocateInfo::default() .descriptor_pool(pool) .set_layouts(&layouts); // SAFETY: The pool and layout are live on this logical device. - let descriptor_set = unsafe { device.device().allocate_descriptor_sets(&allocate_info) } + let descriptor_sets = unsafe { device.device().allocate_descriptor_sets(&allocate_info) } .map_err(|result| { // SAFETY: Resources were created above on this device and are rolled back once. unsafe { @@ -394,7 +404,7 @@ fn create_texture_descriptor_bundle( context: "vkAllocateDescriptorSets", result, } - })?[0]; + })?; let sampler_info = vk::SamplerCreateInfo::default() .mag_filter(vk::Filter::LINEAR) .min_filter(vk::Filter::LINEAR) @@ -416,19 +426,30 @@ fn create_texture_descriptor_bundle( result, } })?; - let image_info = vk::DescriptorImageInfo::default() - .sampler(sampler) - .image_view(texture.view) - .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL); - let image_infos = [image_info]; - let write = vk::WriteDescriptorSet::default() - .dst_set(descriptor_set) - .dst_binding(0) - .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) - .image_info(&image_infos); - // SAFETY: The descriptor set, sampler and image view are live and the texture upload completed its shader-read transition. - unsafe { device.device().update_descriptor_sets(&[write], &[]) }; - Ok((layout, pool, descriptor_set, sampler)) + let image_infos = textures + .iter() + .map(|texture| { + vk::DescriptorImageInfo::default() + .sampler(sampler) + .image_view(texture.view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + }) + .collect::<Vec<_>>(); + let writes = descriptor_sets + .iter() + .copied() + .zip(image_infos.iter()) + .map(|(descriptor_set, image_info)| { + vk::WriteDescriptorSet::default() + .dst_set(descriptor_set) + .dst_binding(0) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(std::slice::from_ref(image_info)) + }) + .collect::<Vec<_>>(); + // SAFETY: Descriptor sets, sampler and image views are live; every texture upload completed its shader-read transition. + unsafe { device.device().update_descriptor_sets(&writes, &[]) }; + Ok((layout, pool, descriptor_sets, sampler)) } #[allow(clippy::cast_precision_loss)] |
