-
Notifications
You must be signed in to change notification settings - Fork 967
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Presentation Timestamp Correlation (#3240)
Co-authored-by: Jim Blandy <[email protected]>
- Loading branch information
1 parent
f3c5091
commit 5241633
Showing
21 changed files
with
289 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ pub mod conv; | |
pub mod exception; | ||
pub mod factory; | ||
pub mod result; | ||
pub mod time; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#![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 { | ||
fnQueryInterruptTimePrecise: 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 { | ||
fnQueryInterruptTimePrecise, | ||
} => f | ||
.debug_struct("IPresentationManager") | ||
.field( | ||
"QueryInterruptTimePrecise", | ||
&(fnQueryInterruptTimePrecise 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+ | ||
// | ||
// 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 { kernelbase.get(b"QueryInterruptTimePrecise").unwrap() }; | ||
Self::IPresentationManager { | ||
fnQueryInterruptTimePrecise: *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 { | ||
fnQueryInterruptTimePrecise, | ||
} => { | ||
let mut counter = 0; | ||
unsafe { fnQueryInterruptTimePrecise(&mut counter) }; | ||
|
||
// QueryInterruptTimePrecise uses units of 100ns for its tick. | ||
counter as u128 * 100 | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
//! 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. | ||
#[derive(Debug)] | ||
pub struct PresentationTimer { | ||
scale: MachTimebaseInfo, | ||
} | ||
impl PresentationTimer { | ||
/// Generates a new timer. | ||
pub fn new() -> Self { | ||
// Default to 1 / 1 in case 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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.