aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-25 06:35:48 +0300
committerValentin Popov <valentin@popov.link>2026-06-25 10:45:38 +0300
commit8f0dcd7f4ddfbb4a3eb4e0845c06bfb925b92e94 (patch)
treea0b1f5692b76abcadb72f10a6ad838ad2285d7ee
parent97f56c56ba1f809dd1c1fae8fd238f1e7de4c4b9 (diff)
downloadfparkan-8f0dcd7f4ddfbb4a3eb4e0845c06bfb925b92e94.tar.xz
fparkan-8f0dcd7f4ddfbb4a3eb4e0845c06bfb925b92e94.zip
feat(vulkan-smoke): verify macos portability evidence
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/smoke.rs7
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs2
-rw-r--r--apps/fparkan-vulkan-smoke/src/main.rs15
-rw-r--r--xtask/src/main.rs46
4 files changed, 69 insertions, 1 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
index b911b1e..f10cd7c 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/smoke.rs
@@ -13,6 +13,7 @@ use super::{
VulkanSurfaceProbe, VulkanSwapchainProbe, VulkanSwapchainResources, VulkanValidationMessenger,
VulkanValidationReport,
};
+use crate::policy::KHR_PORTABILITY_SUBSET_EXTENSION;
use crate::shader_manifest::{triangle_shader_manifest, validate_shader_manifest};
fn take_runtime_owners_in_dependency_order<Instance, Validation, Surface, Device, Swapchain>(
@@ -142,6 +143,7 @@ impl VulkanSmokeRenderer {
report: VulkanSmokeRendererReport {
shader_manifest_hash: shader_manifest.manifest_hash.clone(),
portability_enumeration: instance_config.enable_portability_enumeration,
+ portability_subset_enabled: false,
device_name: String::new(),
graphics_queue_family: 0,
present_queue_family: 0,
@@ -159,6 +161,11 @@ impl VulkanSmokeRenderer {
.instance
.as_ref()
.is_some_and(|instance| instance.report.create_flags != 0),
+ portability_subset_enabled: device_ref
+ .report
+ .enabled_extensions
+ .iter()
+ .any(|extension| extension == KHR_PORTABILITY_SUBSET_EXTENSION),
device_name: device_ref.report.device_name.clone(),
graphics_queue_family: device_ref.report.graphics_queue_family,
present_queue_family: device_ref.report.present_queue_family,
diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs
index 7c581c3..87d7992 100644
--- a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs
+++ b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs
@@ -29,6 +29,8 @@ pub struct VulkanSmokeRendererReport {
pub shader_manifest_hash: String,
/// Whether portability enumeration was enabled at instance creation.
pub portability_enumeration: bool,
+ /// Whether the logical device enabled `VK_KHR_portability_subset`.
+ pub portability_subset_enabled: bool,
/// Selected device name.
pub device_name: String,
/// Graphics queue-family index.
diff --git a/apps/fparkan-vulkan-smoke/src/main.rs b/apps/fparkan-vulkan-smoke/src/main.rs
index 03d3edb..621a67d 100644
--- a/apps/fparkan-vulkan-smoke/src/main.rs
+++ b/apps/fparkan-vulkan-smoke/src/main.rs
@@ -200,6 +200,7 @@ impl SmokeApp {
commit_sha: current_git_commit_sha(),
git_dirty: current_git_dirty(),
runner_identity: measured_runner_identity(),
+ runner_architecture: actual_architecture(),
rust_toolchain: current_rustc_release(),
target_triple: current_rustc_host_triple(),
platform: actual_platform(),
@@ -264,6 +265,8 @@ impl SmokeApp {
.map_or(0, |value| value.report().swapchain_image_count),
vulkan_portability_enumeration: renderer
.is_some_and(|value| value.report().portability_enumeration),
+ vulkan_portability_subset_enabled: renderer
+ .is_some_and(|value| value.report().portability_subset_enabled),
};
serde_json::to_string_pretty(&smoke_report)
.map(|json| format!("{json}\n"))
@@ -488,6 +491,7 @@ struct SmokeReport<'a> {
commit_sha: String,
git_dirty: bool,
runner_identity: String,
+ runner_architecture: &'static str,
rust_toolchain: String,
target_triple: String,
platform: &'static str,
@@ -518,6 +522,7 @@ struct SmokeReport<'a> {
vulkan_swapchain_height: u32,
vulkan_swapchain_image_count: u32,
vulkan_portability_enumeration: bool,
+ vulkan_portability_subset_enabled: bool,
}
fn actual_platform() -> &'static str {
@@ -529,6 +534,13 @@ fn actual_platform() -> &'static str {
}
}
+fn actual_architecture() -> &'static str {
+ match std::env::consts::ARCH {
+ "arm64" => "aarch64",
+ other => other,
+ }
+}
+
fn current_git_commit_sha() -> String {
Command::new("git")
.args(["rev-parse", "HEAD"])
@@ -692,6 +704,7 @@ mod tests {
commit_sha: "0123456789abcdef0123456789abcdef01234567".to_string(),
git_dirty: false,
runner_identity: "github-actions/12345/stage0-macos".to_string(),
+ runner_architecture: "aarch64",
rust_toolchain: "1.87.0".to_string(),
target_triple: "aarch64-apple-darwin".to_string(),
platform: "macos",
@@ -721,12 +734,14 @@ mod tests {
vulkan_swapchain_height: 540,
vulkan_swapchain_image_count: 3,
vulkan_portability_enumeration: true,
+ vulkan_portability_subset_enabled: true,
})
.expect("smoke report should serialize");
assert!(json.contains("\"schema_version\": \"fparkan-native-smoke-v1\""));
assert!(json.contains("\"validation_vuids\": ["));
assert!(json.contains("\"vulkan_device_name\": \"Apple GPU\""));
+ assert!(json.contains("\"runner_architecture\": \"aarch64\""));
}
#[test]
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 601cc3b..da8c16f 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -1665,6 +1665,8 @@ fn validate_native_smoke_provenance_fields(
expect_bool_field(platform, report, "git_dirty", failures);
expect_bool_field_value(platform, report, "git_dirty", false, failures);
expect_nonempty_string(platform, report, "runner_identity", failures);
+ expect_nonempty_string(platform, report, "runner_architecture", failures);
+ expect_runner_architecture_matches_platform(platform, report, failures);
expect_string_field(
platform,
report,
@@ -1719,6 +1721,22 @@ fn validate_native_smoke_runtime_fields(
2,
failures,
);
+ if platform == "macos" {
+ expect_bool_field_value(
+ platform,
+ report,
+ "vulkan_portability_enumeration",
+ true,
+ failures,
+ );
+ expect_bool_field_value(
+ platform,
+ report,
+ "vulkan_portability_subset_enabled",
+ true,
+ failures,
+ );
+ }
}
fn expect_string_field(
@@ -1815,6 +1833,25 @@ fn expect_target_triple_matches_platform(
}
}
+fn expect_runner_architecture_matches_platform(
+ platform: &str,
+ report: &serde_json::Value,
+ failures: &mut Vec<String>,
+) {
+ let Ok(runner_architecture) = json_string_field(report, "runner_architecture") else {
+ return;
+ };
+ let matches_platform = match platform {
+ "macos" => runner_architecture == "aarch64",
+ _ => !runner_architecture.trim().is_empty(),
+ };
+ if !matches_platform {
+ failures.push(format!(
+ "{platform}: runner_architecture {runner_architecture:?} does not match platform policy"
+ ));
+ }
+}
+
fn expect_u64_at_least(
platform: &str,
report: &serde_json::Value,
@@ -2585,6 +2622,7 @@ mod tests {
"commit_sha": "0123456789abcdef0123456789abcdef01234567",
"git_dirty": false,
"runner_identity": "github-actions/12345/stage0-macos",
+ "runner_architecture": "aarch64",
"rust_toolchain": measured_rust_toolchain_version(),
"target_triple": target_triple,
"platform": platform,
@@ -2608,7 +2646,9 @@ mod tests {
"vulkan_swapchain_status": "created",
"vulkan_swapchain_width": 1280,
"vulkan_swapchain_height": 720,
- "vulkan_swapchain_image_count": 3
+ "vulkan_swapchain_image_count": 3,
+ "vulkan_portability_enumeration": true,
+ "vulkan_portability_subset_enabled": true
}),
)
})
@@ -2626,6 +2666,7 @@ mod tests {
"commit_sha": "unknown",
"git_dirty": true,
"runner_identity": "",
+ "runner_architecture": "x86_64",
"rust_toolchain": measured_rust_toolchain_version(),
"target_triple": "x86_64-unknown-linux-gnu",
"platform": "macos",
@@ -2662,6 +2703,9 @@ mod tests {
&"macos: target_triple \"x86_64-unknown-linux-gnu\" does not match platform"
.to_string()
));
+ assert!(failures.contains(
+ &"macos: runner_architecture \"x86_64\" does not match platform policy".to_string()
+ ));
assert!(failures.contains(&"macos: frames expected >= 300, found 0".to_string()));
assert!(failures
.contains(&"macos: validation_error_count must be an unsigned integer".to_string()));