From b784e9b33a3984c64e84d3e9993c2152675178c6 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 28 Nov 2022 00:34:33 -0500 Subject: [PATCH 01/13] Implement presentation timestamp correlation on mac --- wgpu-core/src/instance.rs | 19 +++++++++++ wgpu-hal/src/empty.rs | 8 +++++ wgpu-hal/src/gles/adapter.rs | 8 +++++ wgpu-hal/src/lib.rs | 10 ++++++ wgpu-hal/src/metal/adapter.rs | 31 ++++++++++++++++++ wgpu-types/src/lib.rs | 37 +++++++++++++++++++++ wgpu/examples/framework.rs | 1 + wgpu/src/backend/direct.rs | 28 ++++++++++++++++ wgpu/src/lib.rs | 60 +++++++++++++++++++++++++++++------ 9 files changed, 193 insertions(+), 9 deletions(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 82468881e2..6283b2069a 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -925,6 +925,25 @@ impl Global { .map_err(|_| InvalidAdapter) } + pub fn adapter_correlate_presentation_timestamp( + &self, + adapter_id: AdapterId, + user_timestamp_function: &mut dyn FnMut(), + ) -> Result + { + let hub = A::hub(self); + let mut token = Token::root(); + let (adapter_guard, _) = hub.adapters.read(&mut token); + let adapter = adapter_guard.get(adapter_id).map_err(|_| InvalidAdapter)?; + + Ok(unsafe { + adapter + .raw + .adapter + .correlate_presentation_timestamp(user_timestamp_function) + }) + } + pub fn adapter_drop(&self, adapter_id: AdapterId) { profiling::scope!("Adapter::drop"); diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index a761ef7fb1..898d29219e 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -93,6 +93,14 @@ impl crate::Adapter for Context { unsafe fn surface_capabilities(&self, surface: &Context) -> Option { None } + + unsafe fn correlate_presentation_timestamp( + &self, + function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp { + function(); + wgt::PresentationTimestamp::INVALID_TIMESTAMP + } } impl crate::Queue for Context { diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 399655febb..702102d477 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -858,6 +858,14 @@ impl crate::Adapter for super::Adapter { None } } + + unsafe fn correlate_presentation_timestamp( + &self, + function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp { + function(); + wgt::PresentationTimestamp::INVALID_TIMESTAMP + } } impl super::AdapterShared { diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index b688e326d6..5241e6103b 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -233,6 +233,16 @@ pub trait Adapter: Send + Sync { /// /// `None` means presentation is not supported for it. unsafe fn surface_capabilities(&self, surface: &A::Surface) -> Option; + + /// Creates a [PresentationTimestamp](wgt::PresentationTimestamp) then immediately calls the user_timestamp_function, + /// allowing the user to correlate the presentation timestamp with another set of timestamps (like `Instant`s). + /// + /// While user_timestamp_function is an FnMut, this is because of higher level internal details. It will only ever be called once + /// and it will unconditionally be called. + unsafe fn correlate_presentation_timestamp( + &self, + user_timestamp_function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp; } pub trait Device: Send + Sync { diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 201b6960b9..041564eeee 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -319,6 +319,37 @@ impl crate::Adapter for super::Adapter { usage: crate::TextureUses::COLOR_TARGET | crate::TextureUses::COPY_DST, //TODO: expose more }) } + + unsafe fn correlate_presentation_timestamp( + &self, + user_tiemstamp_function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp + { + #[repr(C)] + #[derive(Debug)] + struct mach_timebase_info { + numerator: u32, + denominator: u32, + } + extern "C" { + fn mach_timebase_info(out: *mut mach_timebase_info) -> u32; + fn mach_absolute_time() -> u64; + } + + // Get the two timestamps as close as possible to each other. + // Doing timestamp processing _after_ both functions are called. + user_tiemstamp_function(); + let timestamp_base = unsafe { mach_absolute_time() }; + + let mut info = mach_timebase_info { + numerator: 0, + denominator: 0, + }; + unsafe { mach_timebase_info(&mut info) }; + let timestamp_scaled = (timestamp_base as u128 * info.numerator as u128) / info.denominator as u128; + + wgt::PresentationTimestamp(timestamp_scaled) + } } const RESOURCE_HEAP_SUPPORT: &[MTLFeatureSet] = &[ diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 82d5708c12..14d5f73962 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3953,6 +3953,43 @@ pub enum SurfaceStatus { Lost, } +/// Nanosecond timestamp used by the presentation engine. +/// +/// These specific clock depends on the WSI used. +/// +/// +/// +/// +/// +/// +/// +///
WSI +/// Clock +///
IDXGISwapchain +/// QueryPerformanceCounter +///
IPresentationManager +/// QueryInterruptTimePrecise +///
CAMetalLayer +/// mach_absolute_time +///
VK_GOOGLE_display_timing +/// clock_gettime(CLOCK_MONOTONIC) +///
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct PresentationTimestamp( + /// Timestamp in nanoseconds. + pub u128, +); + +impl PresentationTimestamp { + /// A timestamp that is invalid due to the platform not having a timestamp system. + pub const INVALID_TIMESTAMP: Self = Self(u128::MAX); + + /// Returns true if this timestamp is the invalid timestamp. + pub fn is_invalid(self) -> bool { + self == Self::INVALID_TIMESTAMP + } +} + /// RGBA double precision color. /// /// This is not to be used as a generic color type, only for specific wgpu interfaces. diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 76d2c425ee..39b6e1a2d2 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -340,6 +340,7 @@ fn start( } }, event::Event::RedrawRequested(_) => { + dbg!(adapter.correlate_presentation_timestamp(Instant::now)); #[cfg(not(target_arch = "wasm32"))] { accum_time += last_frame_inst.elapsed().as_secs_f32(); diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 7eb0d4eba1..91c7a20c0d 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1063,6 +1063,34 @@ impl crate::Context for Context { } } + fn adapter_correlate_presentation_timestamp( + &self, + adapter: &Self::AdapterId, + user_timestamp_function: F, + ) -> (wgt::PresentationTimestamp, T) + where + F: FnOnce() -> T, + { + // Turns a FnOnce into an FnMut by panicing if it's ever called twice + let mut result = None; + let mut optional_function = Some(user_timestamp_function); + let mut mutable_function = || { + result = Some(optional_function.take().expect( + "correlate_presentation_timestamp function called more than once", + )()) + }; + + let global = &self.0; + match wgc::gfx_select!(*adapter => global.adapter_correlate_presentation_timestamp(*adapter, &mut mutable_function)) + { + Ok(timestamp) => ( + timestamp, + result.expect("correlate_presentation_timestamp function never called"), + ), + Err(err) => self.handle_error_fatal(err, "Adapter::correlate_presentation_timestamp"), + } + } + fn surface_get_capabilities( &self, surface: &Self::SurfaceId, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index ff67365ec6..7ca8bb0c9d 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -33,14 +33,15 @@ pub use wgt::{ DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits, MultisampleState, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, - PresentMode, PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, - RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, - ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, - SurfaceCapabilities, SurfaceConfiguration, SurfaceStatus, TextureAspect, TextureDimension, - TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, - TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, - COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, - QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, + PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, PushConstantRange, + QueryType, RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, ShaderLocation, + ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState, + StorageTextureAccess, SurfaceCapabilities, SurfaceConfiguration, SurfaceStatus, TextureAspect, + TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, + TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, + VertexStepMode, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, + PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, + VERTEX_STRIDE_ALIGNMENT, }; use backend::{BufferMappedRange, Context as C, QueueWriteBuffer}; @@ -209,13 +210,13 @@ trait Context: Debug + Send + Sized + Sync { &self, options: &RequestAdapterOptions<'_>, ) -> Self::RequestAdapterFuture; + fn instance_poll_all_devices(&self, force_wait: bool) -> bool; fn adapter_request_device( &self, adapter: &Self::AdapterId, desc: &DeviceDescriptor, trace_dir: Option<&std::path::Path>, ) -> Self::RequestDeviceFuture; - fn instance_poll_all_devices(&self, force_wait: bool) -> bool; fn adapter_is_surface_supported( &self, adapter: &Self::AdapterId, @@ -230,6 +231,13 @@ trait Context: Debug + Send + Sized + Sync { adapter: &Self::AdapterId, format: TextureFormat, ) -> TextureFormatFeatures; + fn adapter_correlate_presentation_timestamp( + &self, + adapter: &Self::AdapterId, + function: F, + ) -> (PresentationTimestamp, T) + where + F: FnOnce() -> T; fn surface_get_capabilities( &self, @@ -2054,6 +2062,40 @@ impl Adapter { pub fn get_texture_format_features(&self, format: TextureFormat) -> TextureFormatFeatures { Context::adapter_get_texture_format_features(&*self.context, &self.id, format) } + + /// Correleates presentation timestamps with a given user timestamp by generating a presentation timestamp + /// immediately after calling the user's timestamp function. + /// + /// When comparing completely opaque timestamp systems, we need a way of generating timestamps that signal + /// the exact same time. This function allows you to generate a timestamp (such as an [Instant]) at the + /// exact same time as a `PresentationTimestamp` is generated, allowing you to translate from one to another. + /// + /// ```no_run + /// # let adapter: wgpu::Adapter = panic!(); + /// # let some_code = || wgpu::PresentationTimestamp::INVALID_TIMESTAMP; + /// use std::time::{Duration, Instant}; + /// let (presentation, instant) = adapter.correlate_presentation_timestamp(Instant::now); + /// + /// // We can now turn a new presentation timestamp into an Instant. + /// let some_pres_timestamp = some_code(); + /// let duration = Duration::from_nanos((some_pres_timestamp.0 - presentation.0) as u64); + /// let new_instant: Instant = instant + duration; + /// ``` + // + /// [Instant]: std::time::Instant + pub fn correlate_presentation_timestamp( + &self, + user_timestamp_function: F, + ) -> (PresentationTimestamp, T) + where + F: FnOnce() -> T, + { + Context::adapter_correlate_presentation_timestamp( + &*self.context, + &self.id, + user_timestamp_function, + ) + } } impl Device { From 331b18b1891201502e6ac9a36d8bffc8685d2534 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 28 Nov 2022 02:44:41 -0500 Subject: [PATCH 02/13] Vulkan and DXGI --- Cargo.lock | 1 + Cargo.toml | 1 + wgpu-core/src/instance.rs | 3 +- wgpu-hal/Cargo.toml | 5 +- wgpu-hal/src/auxil/dxgi/mod.rs | 1 + wgpu-hal/src/auxil/dxgi/time.rs | 92 +++++++++++++++++++++++++++++++++ wgpu-hal/src/dx11/adapter.rs | 7 +++ wgpu-hal/src/dx12/adapter.rs | 12 +++++ wgpu-hal/src/dx12/mod.rs | 1 + wgpu-hal/src/lib.rs | 4 +- wgpu-hal/src/metal/adapter.rs | 6 +-- wgpu-hal/src/vulkan/adapter.rs | 26 ++++++++++ wgpu/examples/framework.rs | 1 - 13 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 wgpu-hal/src/auxil/dxgi/time.rs diff --git a/Cargo.lock b/Cargo.lock index 0b0361fe8f..2ada10b714 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2856,6 +2856,7 @@ dependencies = [ "gpu-descriptor", "js-sys", "khronos-egl", + "libc", "libloading", "log", "metal", diff --git a/Cargo.toml b/Cargo.toml index 50fd3c2d51..a3ab087fa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ futures-intrusive = "0.4" fxhash = "0.2.1" glam = "0.21.3" libloading = "0.7" +libc = "0.2" log = "0.4" nanorand = { version = "0.7", default-features = false } # Opt out of noise's "default-features" to avoid "image" feature as a dependency count optimization. diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 6283b2069a..ed6f8cf6b5 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -929,8 +929,7 @@ impl Global { &self, adapter_id: AdapterId, user_timestamp_function: &mut dyn FnMut(), - ) -> Result - { + ) -> Result { let hub = A::hub(self); let mut token = Token::root(); let (adapter_guard, _) = hub.adapters.read(&mut token); diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index aa8bbcada9..2f79c2e51e 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -86,7 +86,7 @@ egl = { workspace = true, features = ["static", "no-pkg-config"] } libloading = { workspace = true, optional = true } [target.'cfg(windows)'.dependencies] -winapi = { workspace = true, features = ["libloaderapi", "windef", "winuser", "dcomp"] } +winapi = { workspace = true, features = ["profileapi", "libloaderapi", "windef", "winuser", "dcomp"] } native = { workspace = true, features = ["libloading"], optional = true } [target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies] @@ -99,6 +99,9 @@ wasm-bindgen.workspace = true web-sys = { workspace = true, features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext", "OffscreenCanvas"] } js-sys.workspace = true +[target.'cfg(unix)'.dependencies] +libc.workspace = true + [target.'cfg(target_os = "android")'.dependencies] android_system_properties.workspace = true diff --git a/wgpu-hal/src/auxil/dxgi/mod.rs b/wgpu-hal/src/auxil/dxgi/mod.rs index 09a2b31bf3..559969633c 100644 --- a/wgpu-hal/src/auxil/dxgi/mod.rs +++ b/wgpu-hal/src/auxil/dxgi/mod.rs @@ -2,3 +2,4 @@ pub mod conv; pub mod exception; pub mod factory; pub mod result; +pub mod time; diff --git a/wgpu-hal/src/auxil/dxgi/time.rs b/wgpu-hal/src/auxil/dxgi/time.rs new file mode 100644 index 0000000000..d3206b954d --- /dev/null +++ b/wgpu-hal/src/auxil/dxgi/time.rs @@ -0,0 +1,92 @@ +#![allow(dead_code)] // IPresentationManager is unused currently + +use std::mem; + +use winapi::um::{ + profileapi::{QueryPerformanceCounter, QueryPerformanceFrequency}, + winnt::LARGE_INTEGER, +}; + +pub enum PresentationTimer { + /// DXGI uses QueryPerformanceCounter + DXGI { + /// How many ticks of QPC per second + frequency: u64, + }, + /// IPresentationManager uses QueryInterruptTimePrecise + #[allow(non_snake_case)] + IPresentationManager { + QueryInterruptTimePrecise: unsafe extern "system" fn(*mut winapi::ctypes::c_ulonglong), + }, +} + +impl std::fmt::Debug for PresentationTimer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::DXGI { frequency } => f + .debug_struct("DXGI") + .field("frequency", &frequency) + .finish(), + Self::IPresentationManager { + QueryInterruptTimePrecise, + } => f + .debug_struct("IPresentationManager") + .field( + "QueryInterruptTimePrecise", + &(QueryInterruptTimePrecise as usize), + ) + .finish(), + } + } +} + +impl PresentationTimer { + /// Create a presentation timer using QueryPerformanceFrequency (what DXGI uses for presentation times) + pub fn new_dxgi() -> Self { + let mut frequency: LARGE_INTEGER = unsafe { mem::zeroed() }; + let success = unsafe { QueryPerformanceFrequency(&mut frequency) }; + assert_ne!(success, 0); + + Self::DXGI { + frequency: unsafe { *frequency.QuadPart() } as u64, + } + } + + /// Create a presentation timer using QueryInterruptTimePrecise (what IPresentationManager uses for presentation times) + /// + /// Panics if QueryInterruptTimePrecise isn't found (below Win10) + pub fn new_ipresentation_manager() -> Self { + // We need to load this explicitly, as QueryInterruptTimePrecise is only available on Windows 10+ + let kernel32 = + libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap(); + // No concerns about lifetimes here as kernelbase is always there. + let ptr = unsafe { kernel32.get(b"QueryInterruptTimePrecise").unwrap() }; + Self::IPresentationManager { + QueryInterruptTimePrecise: *ptr, + } + } + + /// Gets the current time in nanoseconds. + pub fn get_timestamp_ns(&self) -> u128 { + // Always do u128 math _after_ hitting the timing function. + match *self { + PresentationTimer::DXGI { frequency } => { + let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() }; + let success = unsafe { QueryPerformanceCounter(&mut counter) }; + assert_ne!(success, 0); + + // counter * (1_000_000_000 / freq) but re-ordered to make more precise + (unsafe { *counter.QuadPart() } as u128 * 1_000_000_000) / frequency as u128 + } + PresentationTimer::IPresentationManager { + QueryInterruptTimePrecise, + } => { + let mut counter = 0; + unsafe { QueryInterruptTimePrecise(&mut counter) }; + + // QueryInterruptTimePrecise uses units of 100ns for its tick. + counter as u128 * 100 + } + } + } +} diff --git a/wgpu-hal/src/dx11/adapter.rs b/wgpu-hal/src/dx11/adapter.rs index d30ba8fa90..17398238ff 100644 --- a/wgpu-hal/src/dx11/adapter.rs +++ b/wgpu-hal/src/dx11/adapter.rs @@ -24,6 +24,13 @@ impl crate::Adapter for super::Adapter { ) -> Option { todo!() } + + unsafe fn correlate_presentation_timestamp( + &self, + user_timestamp_function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp { + todo!() + } } impl super::Adapter { diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 236fec49c3..d0dfe3843f 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -229,6 +229,9 @@ impl super::Adapter { shader_model_support.HighestShaderModel >= d3d12::D3D_SHADER_MODEL_5_1, ); + // TODO: Determine if IPresentationManager is supported + let presentation_timer = auxil::dxgi::time::PresentationTimer::new_dxgi(); + let base = wgt::Limits::default(); Some(crate::ExposedAdapter { @@ -237,6 +240,7 @@ impl super::Adapter { device, library: Arc::clone(library), private_caps, + presentation_timer, workarounds, }, info, @@ -539,4 +543,12 @@ impl crate::Adapter for super::Adapter { composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], }) } + + unsafe fn correlate_presentation_timestamp( + &self, + user_timestamp_function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp { + user_timestamp_function(); + wgt::PresentationTimestamp(self.presentation_timer.get_timestamp_ns()) + } } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 6fdd26dba7..96d68f0512 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -167,6 +167,7 @@ pub struct Adapter { device: native::Device, library: Arc, private_caps: PrivateCapabilities, + presentation_timer: auxil::dxgi::time::PresentationTimer, //Note: this isn't used right now, but we'll need it later. #[allow(unused)] workarounds: Workarounds, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 5241e6103b..5fe4678ee1 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -234,9 +234,9 @@ pub trait Adapter: Send + Sync { /// `None` means presentation is not supported for it. unsafe fn surface_capabilities(&self, surface: &A::Surface) -> Option; - /// Creates a [PresentationTimestamp](wgt::PresentationTimestamp) then immediately calls the user_timestamp_function, + /// Creates a [PresentationTimestamp](wgt::PresentationTimestamp) then immediately calls the user_timestamp_function, /// allowing the user to correlate the presentation timestamp with another set of timestamps (like `Instant`s). - /// + /// /// While user_timestamp_function is an FnMut, this is because of higher level internal details. It will only ever be called once /// and it will unconditionally be called. unsafe fn correlate_presentation_timestamp( diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 041564eeee..cde90e7d07 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -323,8 +323,7 @@ impl crate::Adapter for super::Adapter { unsafe fn correlate_presentation_timestamp( &self, user_tiemstamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp - { + ) -> wgt::PresentationTimestamp { #[repr(C)] #[derive(Debug)] struct mach_timebase_info { @@ -346,7 +345,8 @@ impl crate::Adapter for super::Adapter { denominator: 0, }; unsafe { mach_timebase_info(&mut info) }; - let timestamp_scaled = (timestamp_base as u128 * info.numerator as u128) / info.denominator as u128; + let timestamp_scaled = + (timestamp_base as u128 * info.numerator as u128) / info.denominator as u128; wgt::PresentationTimestamp(timestamp_scaled) } diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 72ae9ce90e..d2ebb85f98 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1582,6 +1582,32 @@ impl crate::Adapter for super::Adapter { composite_alpha_modes: conv::map_vk_composite_alpha(caps.supported_composite_alpha), }) } + + unsafe fn correlate_presentation_timestamp( + &self, + user_timestamp_function: &mut dyn FnMut(), + ) -> wgt::PresentationTimestamp { + #[cfg(unix)] + { + let mut timespec = libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }; + user_timestamp_function(); + unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut timespec); + } + + wgt::PresentationTimestamp( + timespec.tv_sec as u128 * 1_000_000_000 + timespec.tv_nsec as u128, + ) + } + #[cfg(not(unix))] + { + user_timestamp_function(); + wgt::PresentationTimestamp::INVALID_TIMESTAMP + } + } } fn is_format_16bit_norm_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool { diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 39b6e1a2d2..76d2c425ee 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -340,7 +340,6 @@ fn start( } }, event::Event::RedrawRequested(_) => { - dbg!(adapter.correlate_presentation_timestamp(Instant::now)); #[cfg(not(target_arch = "wasm32"))] { accum_time += last_frame_inst.elapsed().as_secs_f32(); From 56dc90ae3dd931fca5f052ba53447b35dc7285aa Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 28 Nov 2022 02:51:21 -0500 Subject: [PATCH 03/13] Fix warnings --- wgpu-types/src/lib.rs | 20 ++++++++++---------- wgpu/src/backend/web.rs | 11 +++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 14d5f73962..93bdd65895 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3959,20 +3959,20 @@ pub enum SurfaceStatus { /// /// /// -/// -/// -/// -/// -///
WSI -/// Clock +/// WSI +/// Clock ///
IDXGISwapchain -/// QueryPerformanceCounter +/// IDXGISwapchain +/// QueryPerformanceCounter ///
IPresentationManager -/// QueryInterruptTimePrecise +/// IPresentationManager +/// QueryInterruptTimePrecise ///
CAMetalLayer -/// mach_absolute_time +/// CAMetalLayer +/// mach_absolute_time ///
VK_GOOGLE_display_timing -/// clock_gettime(CLOCK_MONOTONIC) +/// VK_GOOGLE_display_timing +/// clock_gettime(CLOCK_MONOTONIC) ///
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct PresentationTimestamp( diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 6e4e6d4496..8089d36520 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1322,6 +1322,17 @@ impl crate::Context for Context { format.describe().guaranteed_format_features } + fn adapter_correlate_presentation_timestamp( + &self, + _adapter: &Self::AdapterId, + user_timestamp_function: F, + ) -> (wgt::PresentationTimestamp, T) + where + F: FnOnce() -> T, + { + (wgt::PresentationTimestamp::INVALID_TIMESTAMP, user_timestamp_function()) + } + fn surface_get_capabilities( &self, _surface: &Self::SurfaceId, From 8cc57c1244821c23e82fce469de72929337c14a4 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 28 Nov 2022 02:54:48 -0500 Subject: [PATCH 04/13] More warnings --- wgpu-hal/src/auxil/dxgi/time.rs | 10 +++++----- wgpu/src/backend/web.rs | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/wgpu-hal/src/auxil/dxgi/time.rs b/wgpu-hal/src/auxil/dxgi/time.rs index d3206b954d..c3bb8d552c 100644 --- a/wgpu-hal/src/auxil/dxgi/time.rs +++ b/wgpu-hal/src/auxil/dxgi/time.rs @@ -9,7 +9,7 @@ use winapi::um::{ pub enum PresentationTimer { /// DXGI uses QueryPerformanceCounter - DXGI { + Dxgi { /// How many ticks of QPC per second frequency: u64, }, @@ -23,7 +23,7 @@ pub enum PresentationTimer { impl std::fmt::Debug for PresentationTimer { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self { - Self::DXGI { frequency } => f + Self::Dxgi { frequency } => f .debug_struct("DXGI") .field("frequency", &frequency) .finish(), @@ -47,13 +47,13 @@ impl PresentationTimer { let success = unsafe { QueryPerformanceFrequency(&mut frequency) }; assert_ne!(success, 0); - Self::DXGI { + Self::Dxgi { frequency: unsafe { *frequency.QuadPart() } as u64, } } /// Create a presentation timer using QueryInterruptTimePrecise (what IPresentationManager uses for presentation times) - /// + /// /// Panics if QueryInterruptTimePrecise isn't found (below Win10) pub fn new_ipresentation_manager() -> Self { // We need to load this explicitly, as QueryInterruptTimePrecise is only available on Windows 10+ @@ -70,7 +70,7 @@ impl PresentationTimer { pub fn get_timestamp_ns(&self) -> u128 { // Always do u128 math _after_ hitting the timing function. match *self { - PresentationTimer::DXGI { frequency } => { + PresentationTimer::Dxgi { frequency } => { let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() }; let success = unsafe { QueryPerformanceCounter(&mut counter) }; assert_ne!(success, 0); diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 8089d36520..efb38eb3ad 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1330,7 +1330,10 @@ impl crate::Context for Context { where F: FnOnce() -> T, { - (wgt::PresentationTimestamp::INVALID_TIMESTAMP, user_timestamp_function()) + ( + wgt::PresentationTimestamp::INVALID_TIMESTAMP, + user_timestamp_function(), + ) } fn surface_get_capabilities( From cf07d4253b44d8ac1de18b8f561ce628f3997b0d Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 30 Nov 2022 19:32:35 -0500 Subject: [PATCH 05/13] Move metal timing into its own module --- wgpu-hal/src/metal/adapter.rs | 25 ++--------------------- wgpu-hal/src/metal/mod.rs | 3 +++ wgpu-hal/src/metal/time.rs | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 wgpu-hal/src/metal/time.rs diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index cde90e7d07..6185f222e9 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -324,31 +324,10 @@ impl crate::Adapter for super::Adapter { &self, user_tiemstamp_function: &mut dyn FnMut(), ) -> wgt::PresentationTimestamp { - #[repr(C)] - #[derive(Debug)] - struct mach_timebase_info { - numerator: u32, - denominator: u32, - } - extern "C" { - fn mach_timebase_info(out: *mut mach_timebase_info) -> u32; - fn mach_absolute_time() -> u64; - } - - // Get the two timestamps as close as possible to each other. - // Doing timestamp processing _after_ both functions are called. user_tiemstamp_function(); - let timestamp_base = unsafe { mach_absolute_time() }; - - let mut info = mach_timebase_info { - numerator: 0, - denominator: 0, - }; - unsafe { mach_timebase_info(&mut info) }; - let timestamp_scaled = - (timestamp_base as u128 * info.numerator as u128) / info.denominator as u128; + let timestamp = self.shared.presentation_timer.get_timestamp_ns(); - wgt::PresentationTimestamp(timestamp_scaled) + wgt::PresentationTimestamp(timestamp) } } diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index b36dbe473a..c0b0b5d320 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -18,6 +18,7 @@ mod command; mod conv; mod device; mod surface; +mod time; use std::{ fmt, iter, ops, @@ -252,6 +253,7 @@ struct AdapterShared { disabilities: PrivateDisabilities, private_caps: PrivateCapabilities, settings: Settings, + presentation_timer: time::PresentationTimer, } unsafe impl Send for AdapterShared {} @@ -267,6 +269,7 @@ impl AdapterShared { private_caps, device: Mutex::new(device), settings: Settings::default(), + presentation_timer: time::PresentationTimer::new(), } } } diff --git a/wgpu-hal/src/metal/time.rs b/wgpu-hal/src/metal/time.rs new file mode 100644 index 0000000000..30b821a46e --- /dev/null +++ b/wgpu-hal/src/metal/time.rs @@ -0,0 +1,37 @@ +//! Handling of global timestamps. + +#[repr(C)] +#[derive(Debug)] +struct MachTimebaseInfo { + numerator: u32, + denominator: u32, +} +extern "C" { + fn mach_timebase_info(out: *mut MachTimebaseInfo) -> u32; + fn mach_absolute_time() -> u64; +} + +/// A timer which uses mach_absolute_time to get its time. This is what the metal callbacks use. +pub struct PresentationTimer { + scale: MachTimebaseInfo, +} +impl PresentationTimer { + /// Generates a new timer. + pub fn new() -> Self { + // Default to 1 / 1 incase the call to timebase_info fails. + let mut scale = MachTimebaseInfo { + numerator: 1, + denominator: 1, + }; + unsafe { mach_timebase_info(&mut scale) }; + + Self { scale } + } + + /// Gets the current time in nanoseconds. + pub fn get_timestamp_ns(&self) -> u128 { + let time = unsafe { mach_absolute_time() }; + + (time as u128 * self.scale.numerator as u128) / self.scale.denominator as u128 + } +} From f727c053797cb26ced9d69088da0b37b1450403c Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 30 Nov 2022 19:37:56 -0500 Subject: [PATCH 06/13] Improve documentation and naming --- wgpu-hal/src/auxil/dxgi/time.rs | 16 +++++++++------- wgpu-hal/src/vulkan/adapter.rs | 4 ++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/wgpu-hal/src/auxil/dxgi/time.rs b/wgpu-hal/src/auxil/dxgi/time.rs index c3bb8d552c..33262e9e91 100644 --- a/wgpu-hal/src/auxil/dxgi/time.rs +++ b/wgpu-hal/src/auxil/dxgi/time.rs @@ -16,7 +16,7 @@ pub enum PresentationTimer { /// IPresentationManager uses QueryInterruptTimePrecise #[allow(non_snake_case)] IPresentationManager { - QueryInterruptTimePrecise: unsafe extern "system" fn(*mut winapi::ctypes::c_ulonglong), + fnQueryInterruptTimePrecise: unsafe extern "system" fn(*mut winapi::ctypes::c_ulonglong), }, } @@ -28,7 +28,7 @@ impl std::fmt::Debug for PresentationTimer { .field("frequency", &frequency) .finish(), Self::IPresentationManager { - QueryInterruptTimePrecise, + fnQueryInterruptTimePrecise: QueryInterruptTimePrecise, } => f .debug_struct("IPresentationManager") .field( @@ -57,12 +57,14 @@ impl PresentationTimer { /// Panics if QueryInterruptTimePrecise isn't found (below Win10) pub fn new_ipresentation_manager() -> Self { // We need to load this explicitly, as QueryInterruptTimePrecise is only available on Windows 10+ - let kernel32 = + // + // Docs say it's in kernel32.dll, but it's actually in kernelbase.dll. + let kernelbase = libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap(); // No concerns about lifetimes here as kernelbase is always there. - let ptr = unsafe { kernel32.get(b"QueryInterruptTimePrecise").unwrap() }; + let ptr = unsafe { kernelbase.get(b"QueryInterruptTimePrecise").unwrap() }; Self::IPresentationManager { - QueryInterruptTimePrecise: *ptr, + fnQueryInterruptTimePrecise: *ptr, } } @@ -79,10 +81,10 @@ impl PresentationTimer { (unsafe { *counter.QuadPart() } as u128 * 1_000_000_000) / frequency as u128 } PresentationTimer::IPresentationManager { - QueryInterruptTimePrecise, + fnQueryInterruptTimePrecise, } => { let mut counter = 0; - unsafe { QueryInterruptTimePrecise(&mut counter) }; + unsafe { fnQueryInterruptTimePrecise(&mut counter) }; // QueryInterruptTimePrecise uses units of 100ns for its tick. counter as u128 * 100 diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index d2ebb85f98..f9b1d7f3d0 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1587,6 +1587,10 @@ impl crate::Adapter for super::Adapter { &self, user_timestamp_function: &mut dyn FnMut(), ) -> wgt::PresentationTimestamp { + // VK_GOOGLE_display_timing is the only way to get presentation + // timestamps on vulkan right now and it is only ever available + // on android and linux. This includes mac, but there's no alternative + // on mac, so this is fine. #[cfg(unix)] { let mut timespec = libc::timespec { From 746799bae1c0d3637167909171b38cceee21dd3e Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 30 Nov 2022 19:44:21 -0500 Subject: [PATCH 07/13] Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 416bc11a66..307b5fddfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,6 +91,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non - Implement `Clone` for `ShaderSource` and `ShaderModuleDescriptor` in `wgpu`. By @daxpedda in [#3086](https://github.com/gfx-rs/wgpu/pull/3086). - Add `get_default_config` for `Surface` to simplify user creation of `SurfaceConfiguration`. By @jinleili in [#3034](https://github.com/gfx-rs/wgpu/pull/3034) - Native adapters can now use MSAA x2 and x8 if it's supported , previously only x1 and x4 were supported . By @39ali in [3140](https://github.com/gfx-rs/wgpu/pull/3140) +- Implemented correleation between user timestamps and platform specific presentation timestamps via [`Adapter::correlate_presentation_timestamp`]. By @cwfitzgerald in [#3240](https://github.com/gfx-rs/wgpu/pull/3240) #### GLES @@ -150,7 +151,6 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non - Make `wgpu::TextureFormat::Depth24PlusStencil8` available on all backends by making the feature unconditionally available and the feature unneeded to use the format. By @Healthire and @cwfitzgerald in [#3165](https://github.com/gfx-rs/wgpu/pull/3165) - ## wgpu-0.14.0 (2022-10-05) ### Major Changes From 8a941327496cba1310128d883e0ef17452ebcb03 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 30 Nov 2022 19:50:01 -0500 Subject: [PATCH 08/13] Warnings --- wgpu-hal/src/auxil/dxgi/time.rs | 4 ++-- wgpu-hal/src/metal/time.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/wgpu-hal/src/auxil/dxgi/time.rs b/wgpu-hal/src/auxil/dxgi/time.rs index 33262e9e91..fd99c097d7 100644 --- a/wgpu-hal/src/auxil/dxgi/time.rs +++ b/wgpu-hal/src/auxil/dxgi/time.rs @@ -28,12 +28,12 @@ impl std::fmt::Debug for PresentationTimer { .field("frequency", &frequency) .finish(), Self::IPresentationManager { - fnQueryInterruptTimePrecise: QueryInterruptTimePrecise, + fnQueryInterruptTimePrecise, } => f .debug_struct("IPresentationManager") .field( "QueryInterruptTimePrecise", - &(QueryInterruptTimePrecise as usize), + &(fnQueryInterruptTimePrecise as usize), ) .finish(), } diff --git a/wgpu-hal/src/metal/time.rs b/wgpu-hal/src/metal/time.rs index 30b821a46e..bcb774c2a8 100644 --- a/wgpu-hal/src/metal/time.rs +++ b/wgpu-hal/src/metal/time.rs @@ -12,6 +12,7 @@ extern "C" { } /// A timer which uses mach_absolute_time to get its time. This is what the metal callbacks use. +#[derive(Debug)] pub struct PresentationTimer { scale: MachTimebaseInfo, } From ec0d275f55ad296c224223c518567c1b89209220 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 5 Dec 2022 20:51:13 -0500 Subject: [PATCH 09/13] Names --- wgpu-hal/src/empty.rs | 4 ++-- wgpu-hal/src/gles/adapter.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 898d29219e..84c7a9825f 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -96,9 +96,9 @@ impl crate::Adapter for Context { unsafe fn correlate_presentation_timestamp( &self, - function: &mut dyn FnMut(), + user_timestamp_function: &mut dyn FnMut(), ) -> wgt::PresentationTimestamp { - function(); + user_timestamp_function(); wgt::PresentationTimestamp::INVALID_TIMESTAMP } } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 702102d477..22104ebdf2 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -861,9 +861,9 @@ impl crate::Adapter for super::Adapter { unsafe fn correlate_presentation_timestamp( &self, - function: &mut dyn FnMut(), + user_timestamp_function: &mut dyn FnMut(), ) -> wgt::PresentationTimestamp { - function(); + user_timestamp_function(); wgt::PresentationTimestamp::INVALID_TIMESTAMP } } From 2b17c16a4c954ba974948bf6af88337e8b0e8986 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 16 Dec 2022 02:27:51 -0500 Subject: [PATCH 10/13] Update wgpu-types/src/lib.rs Co-authored-by: Jim Blandy --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 93bdd65895..f333d2d603 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3955,7 +3955,7 @@ pub enum SurfaceStatus { /// Nanosecond timestamp used by the presentation engine. /// -/// These specific clock depends on the WSI used. +/// The specific clock depends on the window system integration (WSI) API used. /// /// /// From 84c0217c07c29c6c91e728976acd4222513da20d Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 16 Dec 2022 02:27:59 -0500 Subject: [PATCH 11/13] Update wgpu-hal/src/metal/time.rs Co-authored-by: Jim Blandy --- wgpu-hal/src/metal/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-hal/src/metal/time.rs b/wgpu-hal/src/metal/time.rs index bcb774c2a8..5c6bec10cd 100644 --- a/wgpu-hal/src/metal/time.rs +++ b/wgpu-hal/src/metal/time.rs @@ -19,7 +19,7 @@ pub struct PresentationTimer { impl PresentationTimer { /// Generates a new timer. pub fn new() -> Self { - // Default to 1 / 1 incase the call to timebase_info fails. + // Default to 1 / 1 in case the call to timebase_info fails. let mut scale = MachTimebaseInfo { numerator: 1, denominator: 1, From 6ddc493dd7cbf058031ac5f745d66d0571fcf977 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 16 Dec 2022 14:12:32 -0500 Subject: [PATCH 12/13] Vastly simplify interface --- wgpu-core/src/instance.rs | 10 ++-------- wgpu-hal/src/dx11/adapter.rs | 5 +---- wgpu-hal/src/dx12/adapter.rs | 6 +----- wgpu-hal/src/empty.rs | 6 +----- wgpu-hal/src/gles/adapter.rs | 6 +----- wgpu-hal/src/lib.rs | 13 ++++--------- wgpu-hal/src/metal/adapter.rs | 6 +----- wgpu-hal/src/vulkan/adapter.rs | 7 +------ wgpu/src/backend/direct.rs | 25 ++++--------------------- wgpu/src/backend/web.rs | 13 +++---------- wgpu/src/lib.rs | 32 ++++++++++---------------------- 11 files changed, 29 insertions(+), 100 deletions(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index ed6f8cf6b5..f139409906 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -925,22 +925,16 @@ impl Global { .map_err(|_| InvalidAdapter) } - pub fn adapter_correlate_presentation_timestamp( + pub fn adapter_get_presentation_timestamp( &self, adapter_id: AdapterId, - user_timestamp_function: &mut dyn FnMut(), ) -> Result { let hub = A::hub(self); let mut token = Token::root(); let (adapter_guard, _) = hub.adapters.read(&mut token); let adapter = adapter_guard.get(adapter_id).map_err(|_| InvalidAdapter)?; - Ok(unsafe { - adapter - .raw - .adapter - .correlate_presentation_timestamp(user_timestamp_function) - }) + Ok(unsafe { adapter.raw.adapter.get_presentation_timestamp() }) } pub fn adapter_drop(&self, adapter_id: AdapterId) { diff --git a/wgpu-hal/src/dx11/adapter.rs b/wgpu-hal/src/dx11/adapter.rs index 17398238ff..a040e087cb 100644 --- a/wgpu-hal/src/dx11/adapter.rs +++ b/wgpu-hal/src/dx11/adapter.rs @@ -25,10 +25,7 @@ impl crate::Adapter for super::Adapter { todo!() } - unsafe fn correlate_presentation_timestamp( - &self, - user_timestamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp { + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp { todo!() } } diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index cf34d79ad0..57b238c9f8 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -545,11 +545,7 @@ impl crate::Adapter for super::Adapter { }) } - unsafe fn correlate_presentation_timestamp( - &self, - user_timestamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp { - user_timestamp_function(); + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp { wgt::PresentationTimestamp(self.presentation_timer.get_timestamp_ns()) } } diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 84c7a9825f..30e8156e84 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -94,11 +94,7 @@ impl crate::Adapter for Context { None } - unsafe fn correlate_presentation_timestamp( - &self, - user_timestamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp { - user_timestamp_function(); + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp { wgt::PresentationTimestamp::INVALID_TIMESTAMP } } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 22104ebdf2..aa7d1f002c 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -859,11 +859,7 @@ impl crate::Adapter for super::Adapter { } } - unsafe fn correlate_presentation_timestamp( - &self, - user_timestamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp { - user_timestamp_function(); + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp { wgt::PresentationTimestamp::INVALID_TIMESTAMP } } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 5fe4678ee1..f9ce21e122 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -234,15 +234,10 @@ pub trait Adapter: Send + Sync { /// `None` means presentation is not supported for it. unsafe fn surface_capabilities(&self, surface: &A::Surface) -> Option; - /// Creates a [PresentationTimestamp](wgt::PresentationTimestamp) then immediately calls the user_timestamp_function, - /// allowing the user to correlate the presentation timestamp with another set of timestamps (like `Instant`s). - /// - /// While user_timestamp_function is an FnMut, this is because of higher level internal details. It will only ever be called once - /// and it will unconditionally be called. - unsafe fn correlate_presentation_timestamp( - &self, - user_timestamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp; + /// Creates a [`PresentationTimestamp`] using the adapter's WSI. + /// + /// [`PresentationTimestamp`]: wgt::PresentationTimestamp + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp; } pub trait Device: Send + Sync { diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 6185f222e9..63264a70d8 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -320,11 +320,7 @@ impl crate::Adapter for super::Adapter { }) } - unsafe fn correlate_presentation_timestamp( - &self, - user_tiemstamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp { - user_tiemstamp_function(); + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp { let timestamp = self.shared.presentation_timer.get_timestamp_ns(); wgt::PresentationTimestamp(timestamp) diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index f9b1d7f3d0..dca8ae0271 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1583,10 +1583,7 @@ impl crate::Adapter for super::Adapter { }) } - unsafe fn correlate_presentation_timestamp( - &self, - user_timestamp_function: &mut dyn FnMut(), - ) -> wgt::PresentationTimestamp { + unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp { // VK_GOOGLE_display_timing is the only way to get presentation // timestamps on vulkan right now and it is only ever available // on android and linux. This includes mac, but there's no alternative @@ -1597,7 +1594,6 @@ impl crate::Adapter for super::Adapter { tv_sec: 0, tv_nsec: 0, }; - user_timestamp_function(); unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut timespec); } @@ -1608,7 +1604,6 @@ impl crate::Adapter for super::Adapter { } #[cfg(not(unix))] { - user_timestamp_function(); wgt::PresentationTimestamp::INVALID_TIMESTAMP } } diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 91c7a20c0d..f6ce4e343c 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1063,30 +1063,13 @@ impl crate::Context for Context { } } - fn adapter_correlate_presentation_timestamp( + fn adapter_get_presentation_timestamp( &self, adapter: &Self::AdapterId, - user_timestamp_function: F, - ) -> (wgt::PresentationTimestamp, T) - where - F: FnOnce() -> T, - { - // Turns a FnOnce into an FnMut by panicing if it's ever called twice - let mut result = None; - let mut optional_function = Some(user_timestamp_function); - let mut mutable_function = || { - result = Some(optional_function.take().expect( - "correlate_presentation_timestamp function called more than once", - )()) - }; - + ) -> wgt::PresentationTimestamp { let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_correlate_presentation_timestamp(*adapter, &mut mutable_function)) - { - Ok(timestamp) => ( - timestamp, - result.expect("correlate_presentation_timestamp function never called"), - ), + match wgc::gfx_select!(*adapter => global.adapter_get_presentation_timestamp(*adapter)) { + Ok(timestamp) => timestamp, Err(err) => self.handle_error_fatal(err, "Adapter::correlate_presentation_timestamp"), } } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index efb38eb3ad..93b4a65370 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1322,18 +1322,11 @@ impl crate::Context for Context { format.describe().guaranteed_format_features } - fn adapter_correlate_presentation_timestamp( + fn adapter_get_presentation_timestamp( &self, _adapter: &Self::AdapterId, - user_timestamp_function: F, - ) -> (wgt::PresentationTimestamp, T) - where - F: FnOnce() -> T, - { - ( - wgt::PresentationTimestamp::INVALID_TIMESTAMP, - user_timestamp_function(), - ) + ) -> wgt::PresentationTimestamp { + wgt::PresentationTimestamp::INVALID_TIMESTAMP } fn surface_get_capabilities( diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index e2c631e8a4..fb1cb6987e 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -231,13 +231,10 @@ trait Context: Debug + Send + Sized + Sync { adapter: &Self::AdapterId, format: TextureFormat, ) -> TextureFormatFeatures; - fn adapter_correlate_presentation_timestamp( + fn adapter_get_presentation_timestamp( &self, adapter: &Self::AdapterId, - function: F, - ) -> (PresentationTimestamp, T) - where - F: FnOnce() -> T; + ) -> PresentationTimestamp; fn surface_get_capabilities( &self, @@ -2087,18 +2084,19 @@ impl Adapter { Context::adapter_get_texture_format_features(&*self.context, &self.id, format) } - /// Correleates presentation timestamps with a given user timestamp by generating a presentation timestamp - /// immediately after calling the user's timestamp function. + /// Generates a timestamp using the clock used by the presentation engine. /// /// When comparing completely opaque timestamp systems, we need a way of generating timestamps that signal - /// the exact same time. This function allows you to generate a timestamp (such as an [Instant]) at the - /// exact same time as a `PresentationTimestamp` is generated, allowing you to translate from one to another. + /// the exact same time. You can do this by calling your own timestamp function immediately after a call to + /// this function. This should result in timestamps that are 0.5 to 5 microseconds apart. There are locks + /// that must be taken during the call, so don't call your function before. /// /// ```no_run /// # let adapter: wgpu::Adapter = panic!(); /// # let some_code = || wgpu::PresentationTimestamp::INVALID_TIMESTAMP; /// use std::time::{Duration, Instant}; - /// let (presentation, instant) = adapter.correlate_presentation_timestamp(Instant::now); + /// let presentation = adapter.get_presentation_timestamp(); + /// let instant = Instant::now(); /// /// // We can now turn a new presentation timestamp into an Instant. /// let some_pres_timestamp = some_code(); @@ -2107,18 +2105,8 @@ impl Adapter { /// ``` // /// [Instant]: std::time::Instant - pub fn correlate_presentation_timestamp( - &self, - user_timestamp_function: F, - ) -> (PresentationTimestamp, T) - where - F: FnOnce() -> T, - { - Context::adapter_correlate_presentation_timestamp( - &*self.context, - &self.id, - user_timestamp_function, - ) + pub fn get_presentation_timestamp(&self) -> PresentationTimestamp { + Context::adapter_get_presentation_timestamp(&*self.context, &self.id) } } From 9bc566b3b6b01e1bb822e7a88356395dcb4e786e Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 20 Dec 2022 12:39:05 -0500 Subject: [PATCH 13/13] Update CHANGELOG.md Co-authored-by: Jim Blandy --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1df842a769..d795621fd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,7 +140,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non - Implement `Clone` for `ShaderSource` and `ShaderModuleDescriptor` in `wgpu`. By @daxpedda in [#3086](https://github.com/gfx-rs/wgpu/pull/3086). - Add `get_default_config` for `Surface` to simplify user creation of `SurfaceConfiguration`. By @jinleili in [#3034](https://github.com/gfx-rs/wgpu/pull/3034) - Native adapters can now use MSAA x2 and x8 if it's supported , previously only x1 and x4 were supported . By @39ali in [3140](https://github.com/gfx-rs/wgpu/pull/3140) -- Implemented correleation between user timestamps and platform specific presentation timestamps via [`Adapter::correlate_presentation_timestamp`]. By @cwfitzgerald in [#3240](https://github.com/gfx-rs/wgpu/pull/3240) +- Implemented correleation between user timestamps and platform specific presentation timestamps via [`Adapter::get_presentation_timestamp`]. By @cwfitzgerald in [#3240](https://github.com/gfx-rs/wgpu/pull/3240) - Added support for `Features::SHADER_PRIMITIVE_INDEX` on all backends. By @cwfitzgerald in [#3272](https://github.com/gfx-rs/wgpu/pull/3272) #### GLES