feat: require created Vulkan smoke surface

This commit is contained in:
2026-06-23 23:59:07 +04:00
parent 4d19728c39
commit 0e127117e9
4 changed files with 74 additions and 21 deletions
+70 -19
View File
@@ -14,8 +14,8 @@
use fparkan_platform::{NativeWindowHandles, WindowPort}; use fparkan_platform::{NativeWindowHandles, WindowPort};
use fparkan_platform_winit::{probe_smoke_window, WinitWindowPlan}; use fparkan_platform_winit::{probe_smoke_window, WinitWindowPlan};
use fparkan_render_vulkan::{ use fparkan_render_vulkan::{
create_vulkan_instance_probe, plan_vulkan_surface, probe_vulkan_loader, create_vulkan_instance_probe, create_vulkan_surface_probe, probe_vulkan_loader,
triangle_shader_manifest, validate_shader_manifest, VulkanInstanceConfig, triangle_shader_manifest, validate_shader_manifest, VulkanInstanceConfig, VulkanInstanceProbe,
}; };
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
@@ -215,8 +215,8 @@ impl VulkanBootstrapProbe {
let mut probe = Self::probe_loader(); let mut probe = Self::probe_loader();
let window_handles = probe.probe_window(options); let window_handles = probe.probe_window(options);
probe.probe_instance(options); let instance = probe.probe_instance(options);
probe.probe_surface(options, window_handles); probe.probe_surface(options, instance.as_ref(), window_handles);
probe probe
} }
@@ -303,7 +303,7 @@ impl VulkanBootstrapProbe {
} }
} }
fn probe_instance(&mut self, options: &SmokeOptions) { fn probe_instance(&mut self, options: &SmokeOptions) -> Option<VulkanInstanceProbe> {
if options.probes.vulkan.includes_instance() if options.probes.vulkan.includes_instance()
&& self.loader_status == VulkanLoaderStatus::Available && self.loader_status == VulkanLoaderStatus::Available
{ {
@@ -313,6 +313,7 @@ impl VulkanBootstrapProbe {
Ok(instance) => { Ok(instance) => {
self.instance_status = VulkanInstanceStatus::Created; self.instance_status = VulkanInstanceStatus::Created;
self.portability_enumeration = instance.report.create_flags != 0; self.portability_enumeration = instance.report.create_flags != 0;
return Some(instance);
} }
Err(err) => { Err(err) => {
self.instance_status = VulkanInstanceStatus::Failed; self.instance_status = VulkanInstanceStatus::Failed;
@@ -320,23 +321,30 @@ impl VulkanBootstrapProbe {
} }
} }
} }
None
} }
fn probe_surface( fn probe_surface(
&mut self, &mut self,
options: &SmokeOptions, options: &SmokeOptions,
instance: Option<&VulkanInstanceProbe>,
window_handles: Option<NativeWindowHandles>, window_handles: Option<NativeWindowHandles>,
) { ) {
if options.probes.vulkan.includes_surface() if options.probes.vulkan.includes_surface()
&& self.instance_status == VulkanInstanceStatus::Created && self.instance_status == VulkanInstanceStatus::Created
{ {
match plan_vulkan_surface(window_handles) { match instance
.ok_or_else(|| "Vulkan instance probe was not retained".to_string())
.and_then(|instance| {
create_vulkan_surface_probe(instance, window_handles)
.map_err(|err| err.to_string())
}) {
Ok(_) => { Ok(_) => {
self.surface_status = VulkanSurfaceStatus::Planned; self.surface_status = VulkanSurfaceStatus::Created;
} }
Err(err) => { Err(err) => {
self.surface_status = VulkanSurfaceStatus::MissingWindowHandles; self.surface_status = VulkanSurfaceStatus::Failed;
self.surface_error = Some(err.to_string()); self.surface_error = Some(err);
} }
} }
} }
@@ -399,16 +407,16 @@ impl WinitWindowStatus {
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum VulkanSurfaceStatus { enum VulkanSurfaceStatus {
Skipped, Skipped,
Planned, Created,
MissingWindowHandles, Failed,
} }
impl VulkanSurfaceStatus { impl VulkanSurfaceStatus {
const fn as_str(self) -> &'static str { const fn as_str(self) -> &'static str {
match self { match self {
Self::Skipped => "skipped", Self::Skipped => "skipped",
Self::Planned => "planned", Self::Created => "created",
Self::MissingWindowHandles => "missing_window_handles", Self::Failed => "failed",
} }
} }
} }
@@ -511,7 +519,7 @@ fn validate_smoke_options(
"passed native smoke report requires successful --probe-window".to_string(), "passed native smoke report requires successful --probe-window".to_string(),
); );
} }
if bootstrap.surface_status != VulkanSurfaceStatus::Planned { if bootstrap.surface_status != VulkanSurfaceStatus::Created {
return Err( return Err(
"passed native smoke report requires successful --probe-surface".to_string(), "passed native smoke report requires successful --probe-surface".to_string(),
); );
@@ -757,7 +765,7 @@ mod tests {
window_width: Some(1280), window_width: Some(1280),
window_height: Some(720), window_height: Some(720),
window_error: None, window_error: None,
surface_status: VulkanSurfaceStatus::Planned, surface_status: VulkanSurfaceStatus::Created,
surface_error: None, surface_error: None,
}, },
), ),
@@ -840,7 +848,7 @@ mod tests {
window_width: Some(1280), window_width: Some(1280),
window_height: Some(720), window_height: Some(720),
window_error: None, window_error: None,
surface_status: VulkanSurfaceStatus::Planned, surface_status: VulkanSurfaceStatus::Created,
surface_error: None, surface_error: None,
}, },
), ),
@@ -926,7 +934,7 @@ mod tests {
window_width: None, window_width: None,
window_height: None, window_height: None,
window_error: None, window_error: None,
surface_status: VulkanSurfaceStatus::Planned, surface_status: VulkanSurfaceStatus::Created,
surface_error: None, surface_error: None,
}, },
), ),
@@ -978,6 +986,49 @@ mod tests {
); );
} }
#[test]
fn rejects_passed_with_failed_surface() {
let options = SmokeOptions::parse(&strings(&[
"--platform",
"linux",
"--out",
"target/native.json",
"--status",
"passed",
"--frames",
"300",
"--resize-count",
"1",
"--swapchain-recreate-count",
"1",
"--validation-error-count",
"0",
"--probe-surface",
]))
.expect("options");
assert_eq!(
validate_smoke_options(
&options,
&VulkanBootstrapProbe {
loader_status: VulkanLoaderStatus::Available,
instance_api: Some("1.3.0".to_string()),
loader_error: None,
instance_status: VulkanInstanceStatus::Created,
instance_error: None,
portability_enumeration: false,
window_status: WinitWindowStatus::Created,
window_width: Some(1280),
window_height: Some(720),
window_error: None,
surface_status: VulkanSurfaceStatus::Failed,
surface_error: Some("Vulkan surface creation failed".to_string()),
},
),
Err("passed native smoke report requires successful --probe-surface".to_string())
);
}
#[test] #[test]
fn blocked_report_includes_shader_manifest_and_bootstrap_status() -> Result<(), String> { fn blocked_report_includes_shader_manifest_and_bootstrap_status() -> Result<(), String> {
let options = SmokeOptions::parse(&strings(&[ let options = SmokeOptions::parse(&strings(&[
@@ -1004,7 +1055,7 @@ mod tests {
window_width: Some(1280), window_width: Some(1280),
window_height: Some(720), window_height: Some(720),
window_error: None, window_error: None,
surface_status: VulkanSurfaceStatus::MissingWindowHandles, surface_status: VulkanSurfaceStatus::Failed,
surface_error: Some( surface_error: Some(
"native window/display handles are required for Vulkan surface creation" "native window/display handles are required for Vulkan surface creation"
.to_string(), .to_string(),
@@ -1029,7 +1080,7 @@ mod tests {
assert!(json.contains("\"window_width\": 1280")); assert!(json.contains("\"window_width\": 1280"));
assert!(json.contains("\"window_height\": 720")); assert!(json.contains("\"window_height\": 720"));
assert!(json.contains("\"window_error\": null")); assert!(json.contains("\"window_error\": null"));
assert!(json.contains("\"vulkan_surface_status\": \"missing_window_handles\"")); assert!(json.contains("\"vulkan_surface_status\": \"failed\""));
assert!(json.contains( assert!(json.contains(
"\"vulkan_surface_error\": \"native window/display handles are required for Vulkan surface creation\"" "\"vulkan_surface_error\": \"native window/display handles are required for Vulkan surface creation\""
)); ));
+1
View File
@@ -59,6 +59,7 @@ S0-VK-026 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_wi
S0-VK-027 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_swapchain_recreation blocked_report_includes_shader_manifest_and_bootstrap_status S0-VK-027 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_swapchain_recreation blocked_report_includes_shader_manifest_and_bootstrap_status
S0-VK-028 covered cargo test -p fparkan-vulkan-smoke --offline reports_rustc_host_triple blocked_report_includes_shader_manifest_and_bootstrap_status S0-VK-028 covered cargo test -p fparkan-vulkan-smoke --offline reports_rustc_host_triple blocked_report_includes_shader_manifest_and_bootstrap_status
S0-VK-029 covered cargo test -p xtask --offline native_smoke_audit_accepts_complete_three_platform_pass native_smoke_audit_rejects_blocked_or_incomplete_reports S0-VK-029 covered cargo test -p xtask --offline native_smoke_audit_accepts_complete_three_platform_pass native_smoke_audit_rejects_blocked_or_incomplete_reports
S0-VK-030 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_with_failed_surface
S0-LIMIT-001 covered cargo test -p fparkan-binary --offline rejects_count_stride_overflow S0-LIMIT-001 covered cargo test -p fparkan-binary --offline rejects_count_stride_overflow
S0-LIMIT-002 covered cargo test -p fparkan-binary --offline rejects_oversized_declared_allocation_before_read S0-LIMIT-002 covered cargo test -p fparkan-binary --offline rejects_oversized_declared_allocation_before_read
L1-P1-NRES-001 covered cargo test -p fparkan-nres --offline licensed_corpora_nres_roundtrip_gates L1-P1-NRES-001 covered cargo test -p fparkan-nres --offline licensed_corpora_nres_roundtrip_gates
1 # Acceptance coverage manifest.
59 S0-VK-027
60 S0-VK-028
61 S0-VK-029
62 S0-VK-030
63 S0-LIMIT-001
64 S0-LIMIT-002
65 L1-P1-NRES-001
+1
View File
@@ -59,6 +59,7 @@
`S0-VK-027` `S0-VK-027`
`S0-VK-028` `S0-VK-028`
`S0-VK-029` `S0-VK-029`
`S0-VK-030`
`S0-LIMIT-001` `S0-LIMIT-001`
`S0-LIMIT-002` `S0-LIMIT-002`
`L1-P1-NRES-001` `L1-P1-NRES-001`
+2 -2
View File
@@ -1532,7 +1532,7 @@ fn validate_native_smoke_report(
platform, platform,
report, report,
"vulkan_surface_status", "vulkan_surface_status",
"planned", "created",
failures, failures,
); );
expect_u64_at_least(platform, report, "frames", 300, failures); expect_u64_at_least(platform, report, "frames", 300, failures);
@@ -2233,7 +2233,7 @@ mod tests {
"vulkan_loader_status": "available", "vulkan_loader_status": "available",
"vulkan_instance_status": "created", "vulkan_instance_status": "created",
"window_status": "created", "window_status": "created",
"vulkan_surface_status": "planned" "vulkan_surface_status": "created"
}), }),
) )
}) })