From f9a13298c0d5ef9bc0df968d178983506c24c0a6 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Sat, 18 Jul 2026 09:05:20 +0400 Subject: feat(vulkan): capture swapchain pixels --- .../src/ffi/swapchain_resources.rs | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs') diff --git a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs index 529214d..6d87687 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs @@ -16,6 +16,8 @@ use super::{ pub(super) struct VulkanSwapchainResources { pub(super) image_views: Vec, + pub(super) images: Vec, + pub(super) readback_buffers: Vec, pub(super) depth_attachment: VulkanDepthAttachment, pub(super) render_pass: vk::RenderPass, pub(super) pipeline_layout: vk::PipelineLayout, @@ -31,6 +33,7 @@ pub(super) struct VulkanSwapchainResources { struct PartialSwapchainResources { image_views: Vec, + readback_buffers: Vec, depth_attachment: Option, render_pass: Option, pipeline_layout: Option, @@ -71,6 +74,7 @@ pub(super) fn create_swapchain_resources( &images, swapchain.report.plan.format.format, )?, + readback_buffers: Vec::new(), depth_attachment: None, render_pass: None, pipeline_layout: None, @@ -127,6 +131,30 @@ pub(super) fn create_swapchain_resources( } }; partial.framebuffers = framebuffers; + if vk::ImageUsageFlags::from_raw(swapchain.report.plan.image_usage) + .contains(vk::ImageUsageFlags::TRANSFER_SRC) + { + let byte_len = usize::try_from(swapchain.report.plan.extent.0) + .ok() + .and_then(|width| { + usize::try_from(swapchain.report.plan.extent.1) + .ok() + .and_then(|height| width.checked_mul(height)) + }) + .and_then(|pixels| pixels.checked_mul(4)) + .ok_or(VulkanSmokeRendererError::InvalidStaticMesh { + context: "swapchain readback byte length", + })?; + for _ in &images { + match super::create_readback_buffer(instance, device, byte_len) { + Ok(buffer) => partial.readback_buffers.push(buffer), + Err(error) => { + destroy_partial_swapchain_resources(device, command_pool, partial); + return Err(error); + } + } + } + } reset_reusable_command_pool(device, command_pool, reuse_command_pool)?; let command_buffers = match allocate_command_buffers( device, @@ -150,6 +178,8 @@ pub(super) fn create_swapchain_resources( })?; Ok(VulkanSwapchainResources { image_views: partial.image_views, + images, + readback_buffers: partial.readback_buffers, depth_attachment, render_pass, pipeline_layout, @@ -795,6 +825,10 @@ pub(super) fn destroy_swapchain_resources( for image_view in resources.image_views { device.device().destroy_image_view(image_view, None); } + for buffer in resources.readback_buffers { + device.device().destroy_buffer(buffer.buffer, None); + device.device().free_memory(buffer.memory, None); + } } } @@ -843,5 +877,9 @@ fn destroy_partial_swapchain_resources( for image_view in partial.image_views { device.device().destroy_image_view(image_view, None); } + for buffer in partial.readback_buffers { + device.device().destroy_buffer(buffer.buffer, None); + device.device().free_memory(buffer.memory, None); + } } } -- cgit v1.2.3