fix(vulkan-smoke): track bootstrap timeout evidence
This commit is contained in:
@@ -58,8 +58,9 @@ pub use self::runtime::{
|
|||||||
VulkanLogicalDeviceReport,
|
VulkanLogicalDeviceReport,
|
||||||
};
|
};
|
||||||
pub use self::smoke_types::{
|
pub use self::smoke_types::{
|
||||||
VulkanSmokeFrameOutcome, VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo,
|
VulkanSmokeBootstrapProgress, VulkanSmokeBootstrapSnapshot, VulkanSmokeFrameOutcome,
|
||||||
VulkanSmokeRendererError, VulkanSmokeRendererReport, VulkanValidationReport,
|
VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo, VulkanSmokeRendererError,
|
||||||
|
VulkanSmokeRendererReport, VulkanValidationReport,
|
||||||
};
|
};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use self::surface::extension_name;
|
use self::surface::extension_name;
|
||||||
|
|||||||
@@ -76,9 +76,11 @@ impl VulkanSmokeRenderer {
|
|||||||
///
|
///
|
||||||
/// Returns [`VulkanSmokeRendererError`] when Vulkan bootstrap, pipeline creation,
|
/// Returns [`VulkanSmokeRendererError`] when Vulkan bootstrap, pipeline creation,
|
||||||
/// memory allocation, or synchronization resource creation fails.
|
/// memory allocation, or synchronization resource creation fails.
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
create_info: &VulkanSmokeRendererCreateInfo,
|
create_info: &VulkanSmokeRendererCreateInfo,
|
||||||
) -> Result<Self, VulkanSmokeRendererError> {
|
) -> Result<Self, VulkanSmokeRendererError> {
|
||||||
|
let bootstrap_progress = create_info.bootstrap_progress.as_ref();
|
||||||
let shader_manifest = validate_shader_manifest(&triangle_shader_manifest())
|
let shader_manifest = validate_shader_manifest(&triangle_shader_manifest())
|
||||||
.map_err(VulkanSmokeRendererError::ShaderManifest)?;
|
.map_err(VulkanSmokeRendererError::ShaderManifest)?;
|
||||||
let surface_plan = plan_vulkan_surface(Some(create_info.native_handles))
|
let surface_plan = plan_vulkan_surface(Some(create_info.native_handles))
|
||||||
@@ -90,6 +92,10 @@ impl VulkanSmokeRenderer {
|
|||||||
instance_config.enable_validation = create_info.enable_validation;
|
instance_config.enable_validation = create_info.enable_validation;
|
||||||
let instance = create_vulkan_instance_probe(&instance_config)
|
let instance = create_vulkan_instance_probe(&instance_config)
|
||||||
.map_err(VulkanSmokeRendererError::Instance)?;
|
.map_err(VulkanSmokeRendererError::Instance)?;
|
||||||
|
if let Some(progress) = bootstrap_progress {
|
||||||
|
progress.mark_loader_available();
|
||||||
|
progress.mark_instance_created();
|
||||||
|
}
|
||||||
let validation = if create_info.enable_validation {
|
let validation = if create_info.enable_validation {
|
||||||
Some(create_validation_messenger(&instance)?)
|
Some(create_validation_messenger(&instance)?)
|
||||||
} else {
|
} else {
|
||||||
@@ -97,9 +103,15 @@ impl VulkanSmokeRenderer {
|
|||||||
};
|
};
|
||||||
let surface = create_vulkan_surface_probe(&instance, Some(create_info.native_handles))
|
let surface = create_vulkan_surface_probe(&instance, Some(create_info.native_handles))
|
||||||
.map_err(VulkanSmokeRendererError::Surface)?;
|
.map_err(VulkanSmokeRendererError::Surface)?;
|
||||||
|
if let Some(progress) = bootstrap_progress {
|
||||||
|
progress.mark_surface_created();
|
||||||
|
}
|
||||||
let device =
|
let device =
|
||||||
create_vulkan_logical_device_probe(&instance, &surface, create_info.drawable_extent)
|
create_vulkan_logical_device_probe(&instance, &surface, create_info.drawable_extent)
|
||||||
.map_err(VulkanSmokeRendererError::LogicalDevice)?;
|
.map_err(VulkanSmokeRendererError::LogicalDevice)?;
|
||||||
|
if let Some(progress) = bootstrap_progress {
|
||||||
|
progress.mark_logical_device_created();
|
||||||
|
}
|
||||||
let swapchain = create_vulkan_swapchain_probe_for_extent(
|
let swapchain = create_vulkan_swapchain_probe_for_extent(
|
||||||
&instance,
|
&instance,
|
||||||
&surface,
|
&surface,
|
||||||
@@ -108,6 +120,9 @@ impl VulkanSmokeRenderer {
|
|||||||
vk::SwapchainKHR::null(),
|
vk::SwapchainKHR::null(),
|
||||||
)
|
)
|
||||||
.map_err(VulkanSmokeRendererError::Swapchain)?;
|
.map_err(VulkanSmokeRendererError::Swapchain)?;
|
||||||
|
if let Some(progress) = bootstrap_progress {
|
||||||
|
progress.mark_swapchain_created();
|
||||||
|
}
|
||||||
let command_pool = create_command_pool(&device)?;
|
let command_pool = create_command_pool(&device)?;
|
||||||
let vertex_buffer = match create_triangle_vertex_buffer(&instance, &device) {
|
let vertex_buffer = match create_triangle_vertex_buffer(&instance, &device) {
|
||||||
Ok(buffer) => buffer,
|
Ok(buffer) => buffer,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use ash::vk;
|
use ash::vk;
|
||||||
use fparkan_platform::NativeWindowHandles;
|
use fparkan_platform::NativeWindowHandles;
|
||||||
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
VulkanAllocatedBuffer, VulkanFrameSync, VulkanInstanceError, VulkanInstanceProbe,
|
VulkanAllocatedBuffer, VulkanFrameSync, VulkanInstanceError, VulkanInstanceProbe,
|
||||||
@@ -20,8 +22,86 @@ pub struct VulkanSmokeRendererCreateInfo {
|
|||||||
pub drawable_extent: (u32, u32),
|
pub drawable_extent: (u32, u32),
|
||||||
/// Whether validation layers must be enabled.
|
/// Whether validation layers must be enabled.
|
||||||
pub enable_validation: bool,
|
pub enable_validation: bool,
|
||||||
|
/// Optional shared bootstrap progress tracker for failure evidence.
|
||||||
|
pub bootstrap_progress: Option<Arc<VulkanSmokeBootstrapProgress>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shared bootstrap progress used to report partial renderer startup evidence.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct VulkanSmokeBootstrapProgress {
|
||||||
|
flags: AtomicU8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanSmokeBootstrapProgress {
|
||||||
|
/// Marks the Vulkan loader as available.
|
||||||
|
pub fn mark_loader_available(&self) {
|
||||||
|
self.set_flag(BOOTSTRAP_LOADER_AVAILABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the Vulkan instance as created.
|
||||||
|
pub fn mark_instance_created(&self) {
|
||||||
|
self.set_flag(BOOTSTRAP_INSTANCE_CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the Vulkan surface as created.
|
||||||
|
pub fn mark_surface_created(&self) {
|
||||||
|
self.set_flag(BOOTSTRAP_SURFACE_CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks a suitable Vulkan device as selected and the logical device as created.
|
||||||
|
pub fn mark_logical_device_created(&self) {
|
||||||
|
self.set_flag(BOOTSTRAP_DEVICE_SELECTED | BOOTSTRAP_LOGICAL_DEVICE_CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the Vulkan swapchain as created.
|
||||||
|
pub fn mark_swapchain_created(&self) {
|
||||||
|
self.set_flag(BOOTSTRAP_SWAPCHAIN_CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a stable snapshot of the measured bootstrap state.
|
||||||
|
#[must_use]
|
||||||
|
pub fn snapshot(&self) -> VulkanSmokeBootstrapSnapshot {
|
||||||
|
let flags = self.flags.load(Ordering::SeqCst);
|
||||||
|
VulkanSmokeBootstrapSnapshot {
|
||||||
|
loader_available: flags & BOOTSTRAP_LOADER_AVAILABLE != 0,
|
||||||
|
instance_created: flags & BOOTSTRAP_INSTANCE_CREATED != 0,
|
||||||
|
surface_created: flags & BOOTSTRAP_SURFACE_CREATED != 0,
|
||||||
|
device_selected: flags & BOOTSTRAP_DEVICE_SELECTED != 0,
|
||||||
|
logical_device_created: flags & BOOTSTRAP_LOGICAL_DEVICE_CREATED != 0,
|
||||||
|
swapchain_created: flags & BOOTSTRAP_SWAPCHAIN_CREATED != 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_flag(&self, flag: u8) {
|
||||||
|
self.flags.fetch_or(flag, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stable snapshot of measured bootstrap progress.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
#[allow(clippy::struct_excessive_bools)]
|
||||||
|
pub struct VulkanSmokeBootstrapSnapshot {
|
||||||
|
/// Whether the Vulkan loader was resolved.
|
||||||
|
pub loader_available: bool,
|
||||||
|
/// Whether the Vulkan instance was created.
|
||||||
|
pub instance_created: bool,
|
||||||
|
/// Whether the Vulkan surface was created.
|
||||||
|
pub surface_created: bool,
|
||||||
|
/// Whether a suitable Vulkan device was selected.
|
||||||
|
pub device_selected: bool,
|
||||||
|
/// Whether the logical device was created.
|
||||||
|
pub logical_device_created: bool,
|
||||||
|
/// Whether the swapchain was created.
|
||||||
|
pub swapchain_created: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
const BOOTSTRAP_LOADER_AVAILABLE: u8 = 1 << 0;
|
||||||
|
const BOOTSTRAP_INSTANCE_CREATED: u8 = 1 << 1;
|
||||||
|
const BOOTSTRAP_SURFACE_CREATED: u8 = 1 << 2;
|
||||||
|
const BOOTSTRAP_DEVICE_SELECTED: u8 = 1 << 3;
|
||||||
|
const BOOTSTRAP_LOGICAL_DEVICE_CREATED: u8 = 1 << 4;
|
||||||
|
const BOOTSTRAP_SWAPCHAIN_CREATED: u8 = 1 << 5;
|
||||||
|
|
||||||
/// Stable smoke renderer bootstrap report.
|
/// Stable smoke renderer bootstrap report.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct VulkanSmokeRendererReport {
|
pub struct VulkanSmokeRendererReport {
|
||||||
|
|||||||
@@ -13,12 +13,13 @@
|
|||||||
|
|
||||||
use fparkan_platform_winit::{window_native_handles, WinitWindowPlan};
|
use fparkan_platform_winit::{window_native_handles, WinitWindowPlan};
|
||||||
use fparkan_render_vulkan::{
|
use fparkan_render_vulkan::{
|
||||||
VulkanSmokeFrameOutcome, VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo,
|
VulkanSmokeBootstrapProgress, VulkanSmokeFrameOutcome, VulkanSmokeRenderer,
|
||||||
|
VulkanSmokeRendererCreateInfo,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
@@ -52,28 +53,38 @@ fn main() {
|
|||||||
|
|
||||||
fn run(args: &[String]) -> Result<String, String> {
|
fn run(args: &[String]) -> Result<String, String> {
|
||||||
let options = SmokeOptions::parse(args)?;
|
let options = SmokeOptions::parse(args)?;
|
||||||
|
remove_stale_output(&options)?;
|
||||||
let event_loop = EventLoop::new().map_err(|err| format!("winit event loop: {err}"))?;
|
let event_loop = EventLoop::new().map_err(|err| format!("winit event loop: {err}"))?;
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
let completed = Arc::new(AtomicBool::new(false));
|
let completed = Arc::new(AtomicBool::new(false));
|
||||||
spawn_timeout_watchdog(options.clone(), Arc::clone(&completed));
|
let progress = Arc::new(SharedSmokeProgress::default());
|
||||||
let mut app = SmokeApp::new(options, completed);
|
spawn_timeout_watchdog(
|
||||||
|
options.clone(),
|
||||||
|
Arc::clone(&completed),
|
||||||
|
Arc::clone(&progress),
|
||||||
|
);
|
||||||
|
let mut app = SmokeApp::new(options, completed, progress);
|
||||||
if let Err(err) = event_loop.run_app(&mut app) {
|
if let Err(err) = event_loop.run_app(&mut app) {
|
||||||
app.error = Some(format!("winit event loop: {err}"));
|
app.error = Some(format!("winit event loop: {err}"));
|
||||||
}
|
}
|
||||||
app.finish()
|
app.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_timeout_watchdog(options: SmokeOptions, completed: Arc<AtomicBool>) {
|
fn spawn_timeout_watchdog(
|
||||||
|
options: SmokeOptions,
|
||||||
|
completed: Arc<AtomicBool>,
|
||||||
|
progress: Arc<SharedSmokeProgress>,
|
||||||
|
) {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
std::thread::sleep(Duration::from_secs(options.timeout_seconds));
|
std::thread::sleep(Duration::from_secs(options.timeout_seconds));
|
||||||
if completed.load(Ordering::SeqCst) || options.out.exists() {
|
if completed.load(Ordering::SeqCst) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let failure_reason = format!(
|
let failure_reason = format!(
|
||||||
"native smoke timed out after {} seconds",
|
"native smoke timed out after {} seconds",
|
||||||
options.timeout_seconds
|
options.timeout_seconds
|
||||||
);
|
);
|
||||||
if let Ok(report) = render_timeout_failure_report(&options, &failure_reason) {
|
if let Ok(report) = render_timeout_failure_report(&options, &failure_reason, &progress) {
|
||||||
if let Some(parent) = options.out.parent() {
|
if let Some(parent) = options.out.parent() {
|
||||||
let _ = std::fs::create_dir_all(parent);
|
let _ = std::fs::create_dir_all(parent);
|
||||||
}
|
}
|
||||||
@@ -84,6 +95,13 @@ fn spawn_timeout_watchdog(options: SmokeOptions, completed: Arc<AtomicBool>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_stale_output(options: &SmokeOptions) -> Result<(), String> {
|
||||||
|
if !options.out.exists() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
std::fs::remove_file(&options.out).map_err(|err| format!("{}: {err}", options.out.display()))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct SmokeOptions {
|
struct SmokeOptions {
|
||||||
out: PathBuf,
|
out: PathBuf,
|
||||||
@@ -153,6 +171,7 @@ impl SmokeOptions {
|
|||||||
struct SmokeApp {
|
struct SmokeApp {
|
||||||
options: SmokeOptions,
|
options: SmokeOptions,
|
||||||
completed: Arc<AtomicBool>,
|
completed: Arc<AtomicBool>,
|
||||||
|
progress: Arc<SharedSmokeProgress>,
|
||||||
window_id: Option<WindowId>,
|
window_id: Option<WindowId>,
|
||||||
window: Option<Window>,
|
window: Option<Window>,
|
||||||
renderer: Option<VulkanSmokeRenderer>,
|
renderer: Option<VulkanSmokeRenderer>,
|
||||||
@@ -166,10 +185,15 @@ struct SmokeApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SmokeApp {
|
impl SmokeApp {
|
||||||
fn new(options: SmokeOptions, completed: Arc<AtomicBool>) -> Self {
|
fn new(
|
||||||
|
options: SmokeOptions,
|
||||||
|
completed: Arc<AtomicBool>,
|
||||||
|
progress: Arc<SharedSmokeProgress>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
options,
|
options,
|
||||||
completed,
|
completed,
|
||||||
|
progress,
|
||||||
window_id: None,
|
window_id: None,
|
||||||
window: None,
|
window: None,
|
||||||
renderer: None,
|
renderer: None,
|
||||||
@@ -386,7 +410,9 @@ impl SmokeApp {
|
|||||||
fn render_timeout_failure_report(
|
fn render_timeout_failure_report(
|
||||||
options: &SmokeOptions,
|
options: &SmokeOptions,
|
||||||
failure_reason: &str,
|
failure_reason: &str,
|
||||||
|
progress: &SharedSmokeProgress,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
|
let bootstrap = progress.bootstrap.snapshot();
|
||||||
let smoke_report = SmokeReport {
|
let smoke_report = SmokeReport {
|
||||||
schema_version: SCHEMA_VERSION,
|
schema_version: SCHEMA_VERSION,
|
||||||
commit_sha: compiled_commit_sha(),
|
commit_sha: compiled_commit_sha(),
|
||||||
@@ -398,26 +424,54 @@ fn render_timeout_failure_report(
|
|||||||
platform: actual_platform(),
|
platform: actual_platform(),
|
||||||
status: "failed",
|
status: "failed",
|
||||||
failure_reason: Some(failure_reason),
|
failure_reason: Some(failure_reason),
|
||||||
frames: 0,
|
frames: progress.frames_presented.load(Ordering::SeqCst),
|
||||||
resize_count: 0,
|
resize_count: progress.resize_count.load(Ordering::SeqCst),
|
||||||
swapchain_recreate_count: 0,
|
swapchain_recreate_count: progress.swapchain_recreate_count.load(Ordering::SeqCst),
|
||||||
validation_warning_count: 0,
|
validation_warning_count: 0,
|
||||||
validation_error_count: 0,
|
validation_error_count: 0,
|
||||||
validation_vuids: &[],
|
validation_vuids: &[],
|
||||||
requested_frames: options.frames,
|
requested_frames: options.frames,
|
||||||
timeout_seconds: options.timeout_seconds,
|
timeout_seconds: options.timeout_seconds,
|
||||||
shader_manifest_hash: "",
|
shader_manifest_hash: "",
|
||||||
vulkan_loader_status: "failed",
|
vulkan_loader_status: if bootstrap.loader_available {
|
||||||
vulkan_instance_status: "failed",
|
"available"
|
||||||
window_status: "failed",
|
} else {
|
||||||
vulkan_surface_status: "failed",
|
"failed"
|
||||||
vulkan_device_status: "failed",
|
},
|
||||||
|
vulkan_instance_status: if bootstrap.instance_created {
|
||||||
|
"created"
|
||||||
|
} else {
|
||||||
|
"failed"
|
||||||
|
},
|
||||||
|
window_status: if progress.window_created.load(Ordering::SeqCst) {
|
||||||
|
"created"
|
||||||
|
} else {
|
||||||
|
"failed"
|
||||||
|
},
|
||||||
|
vulkan_surface_status: if bootstrap.surface_created {
|
||||||
|
"created"
|
||||||
|
} else {
|
||||||
|
"failed"
|
||||||
|
},
|
||||||
|
vulkan_device_status: if bootstrap.device_selected {
|
||||||
|
"selected"
|
||||||
|
} else {
|
||||||
|
"failed"
|
||||||
|
},
|
||||||
vulkan_device_name: "",
|
vulkan_device_name: "",
|
||||||
vulkan_logical_device_status: "failed",
|
vulkan_logical_device_status: if bootstrap.logical_device_created {
|
||||||
|
"created"
|
||||||
|
} else {
|
||||||
|
"failed"
|
||||||
|
},
|
||||||
vulkan_logical_device_graphics_queue_family: 0,
|
vulkan_logical_device_graphics_queue_family: 0,
|
||||||
vulkan_logical_device_present_queue_family: 0,
|
vulkan_logical_device_present_queue_family: 0,
|
||||||
vulkan_logical_device_enabled_extension_count: 0,
|
vulkan_logical_device_enabled_extension_count: 0,
|
||||||
vulkan_swapchain_status: "failed",
|
vulkan_swapchain_status: if bootstrap.swapchain_created {
|
||||||
|
"created"
|
||||||
|
} else {
|
||||||
|
"failed"
|
||||||
|
},
|
||||||
vulkan_swapchain_width: 0,
|
vulkan_swapchain_width: 0,
|
||||||
vulkan_swapchain_height: 0,
|
vulkan_swapchain_height: 0,
|
||||||
vulkan_swapchain_image_count: 0,
|
vulkan_swapchain_image_count: 0,
|
||||||
@@ -471,6 +525,7 @@ impl ApplicationHandler for SmokeApp {
|
|||||||
native_handles,
|
native_handles,
|
||||||
drawable_extent: (size.width.max(1), size.height.max(1)),
|
drawable_extent: (size.width.max(1), size.height.max(1)),
|
||||||
enable_validation: true,
|
enable_validation: true,
|
||||||
|
bootstrap_progress: Some(Arc::clone(&self.progress.bootstrap)),
|
||||||
}) {
|
}) {
|
||||||
Ok(renderer) => renderer,
|
Ok(renderer) => renderer,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -481,6 +536,7 @@ impl ApplicationHandler for SmokeApp {
|
|||||||
};
|
};
|
||||||
self.last_size = Some((size.width, size.height));
|
self.last_size = Some((size.width, size.height));
|
||||||
self.window_id = Some(window.id());
|
self.window_id = Some(window.id());
|
||||||
|
self.progress.window_created.store(true, Ordering::SeqCst);
|
||||||
self.renderer = Some(renderer);
|
self.renderer = Some(renderer);
|
||||||
self.window = Some(window);
|
self.window = Some(window);
|
||||||
self.schedule_next_redraw();
|
self.schedule_next_redraw();
|
||||||
@@ -511,6 +567,9 @@ impl ApplicationHandler for SmokeApp {
|
|||||||
.is_some_and(|last| last != (size.width, size.height))
|
.is_some_and(|last| last != (size.width, size.height))
|
||||||
{
|
{
|
||||||
self.resize_count = self.resize_count.saturating_add(1);
|
self.resize_count = self.resize_count.saturating_add(1);
|
||||||
|
self.progress
|
||||||
|
.resize_count
|
||||||
|
.store(self.resize_count, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
self.last_size = Some((size.width, size.height));
|
self.last_size = Some((size.width, size.height));
|
||||||
if let Some(renderer) = self.renderer.as_mut() {
|
if let Some(renderer) = self.renderer.as_mut() {
|
||||||
@@ -526,6 +585,9 @@ impl ApplicationHandler for SmokeApp {
|
|||||||
match renderer.draw_frame() {
|
match renderer.draw_frame() {
|
||||||
Ok(VulkanSmokeFrameOutcome::Presented) => {
|
Ok(VulkanSmokeFrameOutcome::Presented) => {
|
||||||
self.frames_presented = self.frames_presented.saturating_add(1);
|
self.frames_presented = self.frames_presented.saturating_add(1);
|
||||||
|
self.progress
|
||||||
|
.frames_presented
|
||||||
|
.store(self.frames_presented, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
Ok(
|
Ok(
|
||||||
VulkanSmokeFrameOutcome::Recreated | VulkanSmokeFrameOutcome::ZeroExtent,
|
VulkanSmokeFrameOutcome::Recreated | VulkanSmokeFrameOutcome::ZeroExtent,
|
||||||
@@ -537,6 +599,9 @@ impl ApplicationHandler for SmokeApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let recreate_count = renderer.swapchain_recreate_count();
|
let recreate_count = renderer.swapchain_recreate_count();
|
||||||
|
self.progress
|
||||||
|
.swapchain_recreate_count
|
||||||
|
.store(recreate_count, Ordering::SeqCst);
|
||||||
let should_request_resize =
|
let should_request_resize =
|
||||||
!self.resize_requested && self.frames_presented >= self.options.resize_frame;
|
!self.resize_requested && self.frames_presented >= self.options.resize_frame;
|
||||||
let should_complete = self.frames_presented >= self.options.frames
|
let should_complete = self.frames_presented >= self.options.frames
|
||||||
@@ -606,6 +671,15 @@ struct SmokeReport<'a> {
|
|||||||
vulkan_portability_subset_enabled: bool,
|
vulkan_portability_subset_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct SharedSmokeProgress {
|
||||||
|
bootstrap: Arc<VulkanSmokeBootstrapProgress>,
|
||||||
|
window_created: AtomicBool,
|
||||||
|
frames_presented: AtomicU32,
|
||||||
|
resize_count: AtomicU32,
|
||||||
|
swapchain_recreate_count: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
fn actual_platform() -> &'static str {
|
fn actual_platform() -> &'static str {
|
||||||
match std::env::consts::OS {
|
match std::env::consts::OS {
|
||||||
"macos" => "macos",
|
"macos" => "macos",
|
||||||
@@ -900,6 +974,7 @@ mod tests {
|
|||||||
timeout_seconds: 7,
|
timeout_seconds: 7,
|
||||||
},
|
},
|
||||||
completed: Arc::new(AtomicBool::new(false)),
|
completed: Arc::new(AtomicBool::new(false)),
|
||||||
|
progress: Arc::new(SharedSmokeProgress::default()),
|
||||||
window_id: None,
|
window_id: None,
|
||||||
window: None,
|
window: None,
|
||||||
renderer: None,
|
renderer: None,
|
||||||
|
|||||||
Reference in New Issue
Block a user