feat: add native smoke window preflight
This commit is contained in:
Generated
+1
@@ -767,6 +767,7 @@ dependencies = [
|
|||||||
name = "fparkan-vulkan-smoke"
|
name = "fparkan-vulkan-smoke"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fparkan-platform-winit",
|
||||||
"fparkan-render-vulkan",
|
"fparkan-render-vulkan",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ use winit::platform::scancode::PhysicalKeyExtScancode;
|
|||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
static NEXT_WINDOW_HANDLE_ID: AtomicU64 = AtomicU64::new(1);
|
static NEXT_WINDOW_HANDLE_ID: AtomicU64 = AtomicU64::new(1);
|
||||||
|
const DEFAULT_SMOKE_WIDTH: u32 = 1280;
|
||||||
|
const DEFAULT_SMOKE_HEIGHT: u32 = 720;
|
||||||
|
|
||||||
fn next_window_id() -> u64 {
|
fn next_window_id() -> u64 {
|
||||||
NEXT_WINDOW_HANDLE_ID.fetch_add(1, Ordering::Relaxed)
|
NEXT_WINDOW_HANDLE_ID.fetch_add(1, Ordering::Relaxed)
|
||||||
@@ -144,6 +146,44 @@ impl EventSource for WinitEventSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Window creation plan for native smoke entrypoints.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct WinitWindowPlan {
|
||||||
|
/// Requested drawable width in physical pixels.
|
||||||
|
pub width: u32,
|
||||||
|
/// Requested drawable height in physical pixels.
|
||||||
|
pub height: u32,
|
||||||
|
/// Whether native window/display handles are required by the caller.
|
||||||
|
pub requires_native_handles: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WinitWindowPlan {
|
||||||
|
/// Returns the Stage 0 native smoke window plan.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn smoke() -> Self {
|
||||||
|
Self {
|
||||||
|
width: DEFAULT_SMOKE_WIDTH,
|
||||||
|
height: DEFAULT_SMOKE_HEIGHT,
|
||||||
|
requires_native_handles: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates the window plan before a native event loop is entered.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`PlatformError`] when the drawable extent is zero.
|
||||||
|
pub fn validate(self) -> Result<Self, PlatformError> {
|
||||||
|
if self.width == 0 || self.height == 0 {
|
||||||
|
return Err(PlatformError::Backend {
|
||||||
|
context: "winit window plan",
|
||||||
|
message: "drawable extent must be non-zero".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Minimal window view over a `winit` window.
|
/// Minimal window view over a `winit` window.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WinitWindow {
|
pub struct WinitWindow {
|
||||||
@@ -276,6 +316,33 @@ mod tests {
|
|||||||
assert!(window.native_handles().is_none());
|
assert!(window.native_handles().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke_window_plan_requires_native_handles_and_nonzero_extent() -> Result<(), PlatformError> {
|
||||||
|
let plan = WinitWindowPlan::smoke().validate()?;
|
||||||
|
|
||||||
|
assert_eq!(plan.width, DEFAULT_SMOKE_WIDTH);
|
||||||
|
assert_eq!(plan.height, DEFAULT_SMOKE_HEIGHT);
|
||||||
|
assert!(plan.requires_native_handles);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke_window_plan_rejects_zero_extent() {
|
||||||
|
let plan = WinitWindowPlan {
|
||||||
|
width: 0,
|
||||||
|
height: DEFAULT_SMOKE_HEIGHT,
|
||||||
|
requires_native_handles: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
plan.validate(),
|
||||||
|
Err(PlatformError::Backend {
|
||||||
|
context: "winit window plan",
|
||||||
|
..
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn window_events_push_expected_platform_events() {
|
fn window_events_push_expected_platform_events() {
|
||||||
let mut source = WinitEventSource::new();
|
let mut source = WinitEventSource::new();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ license.workspace = true
|
|||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
fparkan-platform-winit = { path = "../../adapters/fparkan-platform-winit" }
|
||||||
fparkan-render-vulkan = { path = "../../adapters/fparkan-render-vulkan" }
|
fparkan-render-vulkan = { path = "../../adapters/fparkan-render-vulkan" }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#![allow(clippy::print_stderr, clippy::print_stdout)]
|
#![allow(clippy::print_stderr, clippy::print_stdout)]
|
||||||
//! Native Vulkan smoke runner entrypoint.
|
//! Native Vulkan smoke runner entrypoint.
|
||||||
|
|
||||||
|
use fparkan_platform_winit::WinitWindowPlan;
|
||||||
use fparkan_render_vulkan::{
|
use fparkan_render_vulkan::{
|
||||||
create_vulkan_instance_probe, plan_vulkan_surface, probe_vulkan_loader,
|
create_vulkan_instance_probe, plan_vulkan_surface, probe_vulkan_loader,
|
||||||
triangle_shader_manifest, validate_shader_manifest, VulkanInstanceConfig,
|
triangle_shader_manifest, validate_shader_manifest, VulkanInstanceConfig,
|
||||||
@@ -57,9 +58,7 @@ struct SmokeOptions {
|
|||||||
frames: u32,
|
frames: u32,
|
||||||
resize_count: u32,
|
resize_count: u32,
|
||||||
validation_error_count: Option<u32>,
|
validation_error_count: Option<u32>,
|
||||||
probe_loader: bool,
|
probes: ProbeOptions,
|
||||||
probe_instance: bool,
|
|
||||||
probe_surface: bool,
|
|
||||||
reason: Option<String>,
|
reason: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +70,7 @@ impl SmokeOptions {
|
|||||||
let mut frames = 0;
|
let mut frames = 0;
|
||||||
let mut resize_count = 0;
|
let mut resize_count = 0;
|
||||||
let mut validation_error_count = None;
|
let mut validation_error_count = None;
|
||||||
let mut probe_loader = false;
|
let mut probes = ProbeOptions::default();
|
||||||
let mut probe_instance = false;
|
|
||||||
let mut probe_surface = false;
|
|
||||||
let mut reason = None;
|
let mut reason = None;
|
||||||
let mut iter = args.iter();
|
let mut iter = args.iter();
|
||||||
while let Some(arg) = iter.next() {
|
while let Some(arg) = iter.next() {
|
||||||
@@ -115,16 +112,17 @@ impl SmokeOptions {
|
|||||||
validation_error_count = Some(parse_u32("--validation-error-count", value)?);
|
validation_error_count = Some(parse_u32("--validation-error-count", value)?);
|
||||||
}
|
}
|
||||||
"--probe-loader" => {
|
"--probe-loader" => {
|
||||||
probe_loader = true;
|
probes.vulkan = probes.vulkan.max(VulkanProbeDepth::Loader);
|
||||||
}
|
}
|
||||||
"--probe-instance" => {
|
"--probe-instance" => {
|
||||||
probe_loader = true;
|
probes.vulkan = probes.vulkan.max(VulkanProbeDepth::Instance);
|
||||||
probe_instance = true;
|
}
|
||||||
|
"--probe-window" => {
|
||||||
|
probes.window = true;
|
||||||
}
|
}
|
||||||
"--probe-surface" => {
|
"--probe-surface" => {
|
||||||
probe_loader = true;
|
probes.vulkan = probes.vulkan.max(VulkanProbeDepth::Surface);
|
||||||
probe_instance = true;
|
probes.window = true;
|
||||||
probe_surface = true;
|
|
||||||
}
|
}
|
||||||
"--reason" => {
|
"--reason" => {
|
||||||
let value = iter
|
let value = iter
|
||||||
@@ -142,9 +140,7 @@ impl SmokeOptions {
|
|||||||
frames,
|
frames,
|
||||||
resize_count,
|
resize_count,
|
||||||
validation_error_count,
|
validation_error_count,
|
||||||
probe_loader,
|
probes,
|
||||||
probe_instance,
|
|
||||||
probe_surface,
|
|
||||||
reason,
|
reason,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -156,6 +152,35 @@ fn parse_u32(name: &str, value: &str) -> Result<u32, String> {
|
|||||||
.map_err(|_| format!("invalid {name} value: {value}"))
|
.map_err(|_| format!("invalid {name} value: {value}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||||
|
struct ProbeOptions {
|
||||||
|
vulkan: VulkanProbeDepth,
|
||||||
|
window: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
enum VulkanProbeDepth {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
Loader,
|
||||||
|
Instance,
|
||||||
|
Surface,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanProbeDepth {
|
||||||
|
const fn includes_loader(self) -> bool {
|
||||||
|
matches!(self, Self::Loader | Self::Instance | Self::Surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn includes_instance(self) -> bool {
|
||||||
|
matches!(self, Self::Instance | Self::Surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn includes_surface(self) -> bool {
|
||||||
|
matches!(self, Self::Surface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct VulkanBootstrapProbe {
|
struct VulkanBootstrapProbe {
|
||||||
loader_status: VulkanLoaderStatus,
|
loader_status: VulkanLoaderStatus,
|
||||||
@@ -164,13 +189,17 @@ struct VulkanBootstrapProbe {
|
|||||||
instance_status: VulkanInstanceStatus,
|
instance_status: VulkanInstanceStatus,
|
||||||
instance_error: Option<String>,
|
instance_error: Option<String>,
|
||||||
portability_enumeration: bool,
|
portability_enumeration: bool,
|
||||||
|
window_status: WinitWindowStatus,
|
||||||
|
window_width: Option<u32>,
|
||||||
|
window_height: Option<u32>,
|
||||||
|
window_error: Option<String>,
|
||||||
surface_status: VulkanSurfaceStatus,
|
surface_status: VulkanSurfaceStatus,
|
||||||
surface_error: Option<String>,
|
surface_error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanBootstrapProbe {
|
impl VulkanBootstrapProbe {
|
||||||
fn run(options: &SmokeOptions) -> Self {
|
fn run(options: &SmokeOptions) -> Self {
|
||||||
if !options.probe_loader {
|
if !options.probes.vulkan.includes_loader() {
|
||||||
return Self {
|
return Self {
|
||||||
loader_status: VulkanLoaderStatus::Skipped,
|
loader_status: VulkanLoaderStatus::Skipped,
|
||||||
instance_api: None,
|
instance_api: None,
|
||||||
@@ -178,6 +207,10 @@ impl VulkanBootstrapProbe {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
};
|
};
|
||||||
@@ -191,6 +224,10 @@ impl VulkanBootstrapProbe {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
@@ -201,12 +238,31 @@ impl VulkanBootstrapProbe {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if options.probe_instance && probe.loader_status == VulkanLoaderStatus::Available {
|
if options.probes.window {
|
||||||
|
match WinitWindowPlan::smoke().validate() {
|
||||||
|
Ok(plan) => {
|
||||||
|
probe.window_status = WinitWindowStatus::Planned;
|
||||||
|
probe.window_width = Some(plan.width);
|
||||||
|
probe.window_height = Some(plan.height);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
probe.window_status = WinitWindowStatus::Failed;
|
||||||
|
probe.window_error = Some(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if options.probes.vulkan.includes_instance()
|
||||||
|
&& probe.loader_status == VulkanLoaderStatus::Available
|
||||||
|
{
|
||||||
let config = VulkanInstanceConfig::smoke("fparkan-vulkan-smoke");
|
let config = VulkanInstanceConfig::smoke("fparkan-vulkan-smoke");
|
||||||
probe.portability_enumeration = config.enable_portability_enumeration;
|
probe.portability_enumeration = config.enable_portability_enumeration;
|
||||||
match create_vulkan_instance_probe(&config) {
|
match create_vulkan_instance_probe(&config) {
|
||||||
@@ -220,7 +276,9 @@ impl VulkanBootstrapProbe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options.probe_surface && probe.instance_status == VulkanInstanceStatus::Created {
|
if options.probes.vulkan.includes_surface()
|
||||||
|
&& probe.instance_status == VulkanInstanceStatus::Created
|
||||||
|
{
|
||||||
match plan_vulkan_surface(None) {
|
match plan_vulkan_surface(None) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
probe.surface_status = VulkanSurfaceStatus::Planned;
|
probe.surface_status = VulkanSurfaceStatus::Planned;
|
||||||
@@ -269,6 +327,23 @@ impl VulkanInstanceStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
enum WinitWindowStatus {
|
||||||
|
Skipped,
|
||||||
|
Planned,
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WinitWindowStatus {
|
||||||
|
const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Skipped => "skipped",
|
||||||
|
Self::Planned => "planned",
|
||||||
|
Self::Failed => "failed",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum VulkanSurfaceStatus {
|
enum VulkanSurfaceStatus {
|
||||||
Skipped,
|
Skipped,
|
||||||
@@ -373,6 +448,11 @@ fn validate_smoke_options(
|
|||||||
"passed native smoke report requires successful --probe-instance".to_string(),
|
"passed native smoke report requires successful --probe-instance".to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if bootstrap.window_status != WinitWindowStatus::Planned {
|
||||||
|
return Err(
|
||||||
|
"passed native smoke report requires successful --probe-window".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
if bootstrap.surface_status != VulkanSurfaceStatus::Planned {
|
if bootstrap.surface_status != VulkanSurfaceStatus::Planned {
|
||||||
return Err(
|
return Err(
|
||||||
"passed native smoke report requires successful --probe-surface".to_string(),
|
"passed native smoke report requires successful --probe-surface".to_string(),
|
||||||
@@ -408,6 +488,16 @@ fn render_smoke_report_json(
|
|||||||
.instance_error
|
.instance_error
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or_else(|| "null".to_string(), |value| json_string(value));
|
.map_or_else(|| "null".to_string(), |value| json_string(value));
|
||||||
|
let window_width = bootstrap
|
||||||
|
.window_width
|
||||||
|
.map_or_else(|| "null".to_string(), |value| value.to_string());
|
||||||
|
let window_height = bootstrap
|
||||||
|
.window_height
|
||||||
|
.map_or_else(|| "null".to_string(), |value| value.to_string());
|
||||||
|
let window_error = bootstrap
|
||||||
|
.window_error
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| "null".to_string(), |value| json_string(value));
|
||||||
let surface_error = bootstrap
|
let surface_error = bootstrap
|
||||||
.surface_error
|
.surface_error
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -430,6 +520,10 @@ fn render_smoke_report_json(
|
|||||||
" \"vulkan_instance_status\": \"{}\",\n",
|
" \"vulkan_instance_status\": \"{}\",\n",
|
||||||
" \"vulkan_instance_error\": {},\n",
|
" \"vulkan_instance_error\": {},\n",
|
||||||
" \"vulkan_portability_enumeration\": {},\n",
|
" \"vulkan_portability_enumeration\": {},\n",
|
||||||
|
" \"window_status\": \"{}\",\n",
|
||||||
|
" \"window_width\": {},\n",
|
||||||
|
" \"window_height\": {},\n",
|
||||||
|
" \"window_error\": {},\n",
|
||||||
" \"vulkan_surface_status\": \"{}\",\n",
|
" \"vulkan_surface_status\": \"{}\",\n",
|
||||||
" \"vulkan_surface_error\": {},\n",
|
" \"vulkan_surface_error\": {},\n",
|
||||||
" \"reason\": {}\n",
|
" \"reason\": {}\n",
|
||||||
@@ -454,6 +548,10 @@ fn render_smoke_report_json(
|
|||||||
} else {
|
} else {
|
||||||
"false"
|
"false"
|
||||||
},
|
},
|
||||||
|
bootstrap.window_status.as_str(),
|
||||||
|
window_width,
|
||||||
|
window_height,
|
||||||
|
window_error,
|
||||||
bootstrap.surface_status.as_str(),
|
bootstrap.surface_status.as_str(),
|
||||||
surface_error,
|
surface_error,
|
||||||
reason
|
reason
|
||||||
@@ -526,7 +624,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(options.platform, SmokePlatform::Linux);
|
assert_eq!(options.platform, SmokePlatform::Linux);
|
||||||
assert_eq!(options.status, SmokeStatus::Blocked);
|
assert_eq!(options.status, SmokeStatus::Blocked);
|
||||||
assert!(options.probe_loader);
|
assert_eq!(options.probes.vulkan, VulkanProbeDepth::Loader);
|
||||||
assert_eq!(options.reason.as_deref(), Some("runner unavailable"));
|
assert_eq!(options.reason.as_deref(), Some("runner unavailable"));
|
||||||
validate_smoke_options(
|
validate_smoke_options(
|
||||||
&options,
|
&options,
|
||||||
@@ -537,6 +635,10 @@ mod tests {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
@@ -571,6 +673,10 @@ mod tests {
|
|||||||
instance_status: VulkanInstanceStatus::Created,
|
instance_status: VulkanInstanceStatus::Created,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Planned,
|
||||||
|
window_width: Some(1280),
|
||||||
|
window_height: Some(720),
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Planned,
|
surface_status: VulkanSurfaceStatus::Planned,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
@@ -607,6 +713,10 @@ mod tests {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
@@ -644,6 +754,10 @@ mod tests {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
@@ -653,7 +767,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rejects_passed_without_surface_probe() {
|
fn rejects_passed_without_window_probe() {
|
||||||
let options = SmokeOptions::parse(&strings(&[
|
let options = SmokeOptions::parse(&strings(&[
|
||||||
"--platform",
|
"--platform",
|
||||||
"linux",
|
"linux",
|
||||||
@@ -681,6 +795,52 @@ mod tests {
|
|||||||
instance_status: VulkanInstanceStatus::Created,
|
instance_status: VulkanInstanceStatus::Created,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: false,
|
portability_enumeration: false,
|
||||||
|
window_status: WinitWindowStatus::Skipped,
|
||||||
|
window_width: None,
|
||||||
|
window_height: None,
|
||||||
|
window_error: None,
|
||||||
|
surface_status: VulkanSurfaceStatus::Planned,
|
||||||
|
surface_error: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Err("passed native smoke report requires successful --probe-window".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_passed_without_surface_probe() {
|
||||||
|
let options = SmokeOptions::parse(&strings(&[
|
||||||
|
"--platform",
|
||||||
|
"linux",
|
||||||
|
"--out",
|
||||||
|
"target/native.json",
|
||||||
|
"--status",
|
||||||
|
"passed",
|
||||||
|
"--frames",
|
||||||
|
"300",
|
||||||
|
"--resize-count",
|
||||||
|
"1",
|
||||||
|
"--validation-error-count",
|
||||||
|
"0",
|
||||||
|
"--probe-window",
|
||||||
|
"--probe-instance",
|
||||||
|
]))
|
||||||
|
.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::Planned,
|
||||||
|
window_width: Some(1280),
|
||||||
|
window_height: Some(720),
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::Skipped,
|
surface_status: VulkanSurfaceStatus::Skipped,
|
||||||
surface_error: None,
|
surface_error: None,
|
||||||
},
|
},
|
||||||
@@ -711,6 +871,10 @@ mod tests {
|
|||||||
instance_status: VulkanInstanceStatus::Skipped,
|
instance_status: VulkanInstanceStatus::Skipped,
|
||||||
instance_error: None,
|
instance_error: None,
|
||||||
portability_enumeration: true,
|
portability_enumeration: true,
|
||||||
|
window_status: WinitWindowStatus::Planned,
|
||||||
|
window_width: Some(1280),
|
||||||
|
window_height: Some(720),
|
||||||
|
window_error: None,
|
||||||
surface_status: VulkanSurfaceStatus::MissingWindowHandles,
|
surface_status: VulkanSurfaceStatus::MissingWindowHandles,
|
||||||
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"
|
||||||
@@ -730,6 +894,10 @@ mod tests {
|
|||||||
assert!(json.contains("\"vulkan_instance_status\": \"skipped\""));
|
assert!(json.contains("\"vulkan_instance_status\": \"skipped\""));
|
||||||
assert!(json.contains("\"vulkan_instance_error\": null"));
|
assert!(json.contains("\"vulkan_instance_error\": null"));
|
||||||
assert!(json.contains("\"vulkan_portability_enumeration\": true"));
|
assert!(json.contains("\"vulkan_portability_enumeration\": true"));
|
||||||
|
assert!(json.contains("\"window_status\": \"planned\""));
|
||||||
|
assert!(json.contains("\"window_width\": 1280"));
|
||||||
|
assert!(json.contains("\"window_height\": 720"));
|
||||||
|
assert!(json.contains("\"window_error\": null"));
|
||||||
assert!(json.contains("\"vulkan_surface_status\": \"missing_window_handles\""));
|
assert!(json.contains("\"vulkan_surface_status\": \"missing_window_handles\""));
|
||||||
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\""
|
||||||
@@ -750,9 +918,25 @@ mod tests {
|
|||||||
"runner unavailable",
|
"runner unavailable",
|
||||||
]))?;
|
]))?;
|
||||||
|
|
||||||
assert!(options.probe_loader);
|
assert_eq!(options.probes.vulkan, VulkanProbeDepth::Instance);
|
||||||
assert!(options.probe_instance);
|
assert!(!options.probes.window);
|
||||||
assert!(!options.probe_surface);
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_window_probe_without_vulkan_probes() -> Result<(), String> {
|
||||||
|
let options = SmokeOptions::parse(&strings(&[
|
||||||
|
"--platform",
|
||||||
|
"linux",
|
||||||
|
"--out",
|
||||||
|
"target/native.json",
|
||||||
|
"--probe-window",
|
||||||
|
"--reason",
|
||||||
|
"runner unavailable",
|
||||||
|
]))?;
|
||||||
|
|
||||||
|
assert_eq!(options.probes.vulkan, VulkanProbeDepth::None);
|
||||||
|
assert!(options.probes.window);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,9 +952,8 @@ mod tests {
|
|||||||
"runner unavailable",
|
"runner unavailable",
|
||||||
]))?;
|
]))?;
|
||||||
|
|
||||||
assert!(options.probe_loader);
|
assert_eq!(options.probes.vulkan, VulkanProbeDepth::Surface);
|
||||||
assert!(options.probe_instance);
|
assert!(options.probes.window);
|
||||||
assert!(options.probe_surface);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ S0-CLI-001 covered cargo test -p fparkan-cli --offline stable_exit_codes_are_map
|
|||||||
S0-CLI-002 covered cargo test -p fparkan-cli --offline accepts_json_format_option archive_json_has_schema_version
|
S0-CLI-002 covered cargo test -p fparkan-cli --offline accepts_json_format_option archive_json_has_schema_version
|
||||||
S0-PLAT-001 covered cargo test -p fparkan-platform-winit --offline window_port_reports_default_request_profile
|
S0-PLAT-001 covered cargo test -p fparkan-platform-winit --offline window_port_reports_default_request_profile
|
||||||
S0-PLAT-002 covered cargo clippy -p fparkan-platform -p fparkan-platform-winit --all-targets --all-features --locked -- -D warnings
|
S0-PLAT-002 covered cargo clippy -p fparkan-platform -p fparkan-platform-winit --all-targets --all-features --locked -- -D warnings
|
||||||
|
S0-PLAT-003 covered cargo test -p fparkan-platform-winit --offline smoke_window_plan_requires_native_handles_and_nonzero_extent smoke_window_plan_rejects_zero_extent
|
||||||
S0-VK-001 covered cargo test -p fparkan-render-vulkan --offline backend_tracks_render_request_and_presents
|
S0-VK-001 covered cargo test -p fparkan-render-vulkan --offline backend_tracks_render_request_and_presents
|
||||||
S0-VK-002 covered cargo test -p fparkan-render-vulkan --offline device_scoring_is_deterministic_and_prefers_discrete_unified_queue
|
S0-VK-002 covered cargo test -p fparkan-render-vulkan --offline device_scoring_is_deterministic_and_prefers_discrete_unified_queue
|
||||||
S0-VK-003 covered cargo test -p fparkan-render-vulkan --offline portability_subset_is_reported_and_enabled_when_exposed
|
S0-VK-003 covered cargo test -p fparkan-render-vulkan --offline portability_subset_is_reported_and_enabled_when_exposed
|
||||||
@@ -53,7 +54,7 @@ S0-VK-022 covered cargo test -p fparkan-render-vulkan --offline backend_tracks_r
|
|||||||
S0-VK-023 covered cargo test -p fparkan-vulkan-smoke --offline rejects_false_pass_without_full_evidence blocked_report_includes_shader_manifest_and_bootstrap_status
|
S0-VK-023 covered cargo test -p fparkan-vulkan-smoke --offline rejects_false_pass_without_full_evidence blocked_report_includes_shader_manifest_and_bootstrap_status
|
||||||
S0-VK-024 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_loader_probe formats_vulkan_api_version
|
S0-VK-024 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_loader_probe formats_vulkan_api_version
|
||||||
S0-VK-025 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_instance_probe parses_instance_probe_as_loader_probe
|
S0-VK-025 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_instance_probe parses_instance_probe_as_loader_probe
|
||||||
S0-VK-026 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_surface_probe parses_surface_probe_as_instance_probe
|
S0-VK-026 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_window_probe rejects_passed_without_surface_probe parses_surface_probe_as_instance_probe
|
||||||
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
|
||||||
|
|||||||
|
@@ -28,6 +28,7 @@
|
|||||||
`S0-CLI-002`
|
`S0-CLI-002`
|
||||||
`S0-PLAT-001`
|
`S0-PLAT-001`
|
||||||
`S0-PLAT-002`
|
`S0-PLAT-002`
|
||||||
|
`S0-PLAT-003`
|
||||||
`S0-VK-001`
|
`S0-VK-001`
|
||||||
`S0-VK-002`
|
`S0-VK-002`
|
||||||
`S0-VK-003`
|
`S0-VK-003`
|
||||||
|
|||||||
Reference in New Issue
Block a user