aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-07-18 07:07:45 +0300
committerValentin Popov <valentin@popov.link>2026-07-18 07:07:45 +0300
commitefaba9001fb64eca14db3668c1c5295f078691b5 (patch)
tree867a465547d992bbb4b048cc438f6e97d9398b2d /adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs
parentb915554f3c5695bd8b9707359ffaa51ea8742341 (diff)
downloadfparkan-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.rs81
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)]