aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/ffi
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-07-18 08:08:07 +0300
committerValentin Popov <valentin@popov.link>2026-07-18 08:08:07 +0300
commitb24594c6a20e43b8080a368ad9a20708caddcde6 (patch)
tree4bbe40191b2985a5af495cef520eebc18326ce47 /adapters/fparkan-render-vulkan/src/ffi
parentf9a13298c0d5ef9bc0df968d178983506c24c0a6 (diff)
downloadfparkan-b24594c6a20e43b8080a368ad9a20708caddcde6.tar.xz
fparkan-b24594c6a20e43b8080a368ad9a20708caddcde6.zip
feat(vulkan): export readback artifacts
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi')
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/smoke.rs46
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs15
2 files changed, 44 insertions, 17 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
index eee2f06..5ddfae6 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
@@ -10,10 +10,11 @@ use super::{
create_vulkan_logical_device_probe_for_request, create_vulkan_surface_probe,
create_vulkan_swapchain_probe_for_extent, destroy_allocated_buffer, destroy_allocated_image,
destroy_swapchain_resources, plan_vulkan_surface, readback_buffer_bytes, VulkanAllocatedBuffer,
- VulkanInstanceConfig, VulkanInstanceProbe, VulkanLogicalDeviceProbe, VulkanSmokeFrameOutcome,
- VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo, VulkanSmokeRendererError,
- VulkanSmokeRendererReport, VulkanSmokeShutdownReport, VulkanSurfaceProbe, VulkanSwapchainProbe,
- VulkanSwapchainResources, VulkanValidationMessenger, VulkanValidationReport,
+ VulkanInstanceConfig, VulkanInstanceProbe, VulkanLogicalDeviceProbe, VulkanReadbackArtifact,
+ VulkanSmokeFrameOutcome, VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo,
+ VulkanSmokeRendererError, VulkanSmokeRendererReport, VulkanSmokeShutdownReport,
+ VulkanSurfaceProbe, VulkanSwapchainProbe, VulkanSwapchainResources, VulkanValidationMessenger,
+ VulkanValidationReport,
};
use crate::policy::KHR_PORTABILITY_SUBSET_EXTENSION;
use crate::shader_manifest::{triangle_shader_manifest, validate_shader_manifest};
@@ -845,10 +846,18 @@ impl VulkanSmokeRenderer {
} else {
None
};
- if let Some((byte_count, hash)) = completed_readback {
- self.report.readback_byte_count = byte_count;
- self.report.readback_fnv1a64 = hash;
- }
+ let readback_artifact = completed_readback.map(|bytes| {
+ self.report.readback_byte_count = u64::try_from(bytes.len()).unwrap_or(u64::MAX);
+ self.report.readback_fnv1a64 = fnv1a64(&bytes);
+ VulkanReadbackArtifact {
+ format: self
+ .swapchain_ref()
+ .map_or(0, |swapchain| swapchain.report.plan.format.format),
+ width: self.report.swapchain_extent.0,
+ height: self.report.swapchain_extent.1,
+ bytes,
+ }
+ });
self.destroy_device_owned_resources();
let validation = take_runtime_children_with_validation_snapshot(
&mut self.surface,
@@ -862,6 +871,7 @@ impl VulkanSmokeRenderer {
self.instance.take();
Ok(VulkanSmokeShutdownReport {
renderer_report: self.report.clone(),
+ readback_artifact,
swapchain_recreate_count: self.swapchain_recreate_count,
validation,
})
@@ -870,7 +880,7 @@ impl VulkanSmokeRenderer {
fn completed_readback(
&self,
device: &VulkanLogicalDeviceProbe,
- ) -> Result<Option<(u64, u64)>, VulkanSmokeRendererError> {
+ ) -> Result<Option<Vec<u8>>, VulkanSmokeRendererError> {
let Some(resources) = self.swapchain_resources.as_ref() else {
return Ok(None);
};
@@ -888,17 +898,13 @@ impl VulkanSmokeRenderer {
if resources.readback_buffers.is_empty() {
return Ok(None);
}
- let mut hash = 0xcbf2_9ce4_8422_2325_u64;
- let mut byte_count = 0_u64;
+ let mut artifact =
+ Vec::with_capacity(byte_len.saturating_mul(resources.readback_buffers.len()));
for buffer in &resources.readback_buffers {
let bytes = readback_buffer_bytes(device, buffer, byte_len)?;
- for byte in bytes {
- hash ^= u64::from(byte);
- hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
- }
- byte_count = byte_count.saturating_add(u64::try_from(byte_len).unwrap_or(u64::MAX));
+ artifact.extend_from_slice(&bytes);
}
- Ok(Some((byte_count, hash)))
+ Ok(Some(artifact))
}
fn teardown(&mut self) {
@@ -919,6 +925,12 @@ impl VulkanSmokeRenderer {
}
}
+fn fnv1a64(bytes: &[u8]) -> u64 {
+ bytes.iter().fold(0xcbf2_9ce4_8422_2325_u64, |hash, byte| {
+ (hash ^ u64::from(*byte)).wrapping_mul(0x0000_0100_0000_01b3)
+ })
+}
+
impl Drop for VulkanSmokeRenderer {
fn drop(&mut self) {
self.teardown();
diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs
index ce691b8..60f86e2 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs
@@ -478,11 +478,26 @@ pub struct VulkanValidationReport {
pub vuids: Vec<String>,
}
+/// CPU-owned copy of the final completed swapchain readback buffers.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct VulkanReadbackArtifact {
+ /// Vulkan swapchain format as a raw enum value.
+ pub format: i32,
+ /// Width of each image in pixels.
+ pub width: u32,
+ /// Height of each image in pixels.
+ pub height: u32,
+ /// Concatenated raw four-byte-per-pixel images in swapchain order.
+ pub bytes: Vec<u8>,
+}
+
/// Final smoke renderer shutdown evidence captured after explicit teardown.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VulkanSmokeShutdownReport {
/// Stable renderer bootstrap and swapchain report.
pub renderer_report: VulkanSmokeRendererReport,
+ /// Optional raw GPU readback retained after synchronization and before teardown.
+ pub readback_artifact: Option<VulkanReadbackArtifact>,
/// Measured swapchain recreation count for the completed smoke loop.
pub swapchain_recreate_count: u32,
/// Final validation snapshot captured before the debug messenger is destroyed.