mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-26 00:33:51 +00:00
Implement Presentation Timestamp Correlation (#3240)
Co-authored-by: Jim Blandy <jimb@red-bean.com>
This commit is contained in:
parent
f3c50918c2
commit
5241633b3a
@ -140,6 +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).
|
- 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)
|
- 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)
|
- 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::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)
|
- Added support for `Features::SHADER_PRIMITIVE_INDEX` on all backends. By @cwfitzgerald in [#3272](https://github.com/gfx-rs/wgpu/pull/3272)
|
||||||
|
|
||||||
#### GLES
|
#### GLES
|
||||||
@ -226,7 +227,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)
|
- 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)
|
## wgpu-0.14.0 (2022-10-05)
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2972,6 +2972,7 @@ dependencies = [
|
|||||||
"gpu-descriptor",
|
"gpu-descriptor",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"khronos-egl",
|
"khronos-egl",
|
||||||
|
"libc",
|
||||||
"libloading",
|
"libloading",
|
||||||
"log",
|
"log",
|
||||||
"metal",
|
"metal",
|
||||||
|
@ -58,6 +58,7 @@ futures-intrusive = "0.4"
|
|||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
glam = "0.21.3"
|
glam = "0.21.3"
|
||||||
libloading = "0.7"
|
libloading = "0.7"
|
||||||
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
nanorand = { version = "0.7", default-features = false }
|
nanorand = { version = "0.7", default-features = false }
|
||||||
# Opt out of noise's "default-features" to avoid "image" feature as a dependency count optimization.
|
# Opt out of noise's "default-features" to avoid "image" feature as a dependency count optimization.
|
||||||
|
@ -933,6 +933,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
.map_err(|_| InvalidAdapter)
|
.map_err(|_| InvalidAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn adapter_get_presentation_timestamp<A: HalApi>(
|
||||||
|
&self,
|
||||||
|
adapter_id: AdapterId,
|
||||||
|
) -> Result<wgt::PresentationTimestamp, InvalidAdapter> {
|
||||||
|
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.get_presentation_timestamp() })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn adapter_drop<A: HalApi>(&self, adapter_id: AdapterId) {
|
pub fn adapter_drop<A: HalApi>(&self, adapter_id: AdapterId) {
|
||||||
profiling::scope!("Adapter::drop");
|
profiling::scope!("Adapter::drop");
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ egl = { package = "khronos-egl", version = "4.1", features = ["static", "no-pkg-
|
|||||||
libloading = { version = "0.7", optional = true }
|
libloading = { version = "0.7", optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser", "dcomp"] }
|
winapi = { version = "0.3", features = ["profileapi", "libloaderapi", "windef", "winuser", "dcomp"] }
|
||||||
native = { package = "d3d12", version = "0.5.0", features = ["libloading"], optional = true }
|
native = { package = "d3d12", version = "0.5.0", features = ["libloading"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
|
[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
|
||||||
@ -103,6 +103,9 @@ wasm-bindgen = "0.2.83"
|
|||||||
web-sys = { version = "0.3.60", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext", "OffscreenCanvas"] }
|
web-sys = { version = "0.3.60", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext", "OffscreenCanvas"] }
|
||||||
js-sys = "0.3.60"
|
js-sys = "0.3.60"
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
android_system_properties = "0.1.1"
|
android_system_properties = "0.1.1"
|
||||||
|
|
||||||
|
@ -2,3 +2,4 @@ pub mod conv;
|
|||||||
pub mod exception;
|
pub mod exception;
|
||||||
pub mod factory;
|
pub mod factory;
|
||||||
pub mod result;
|
pub mod result;
|
||||||
|
pub mod time;
|
||||||
|
94
wgpu-hal/src/auxil/dxgi/time.rs
Normal file
94
wgpu-hal/src/auxil/dxgi/time.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,10 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||||||
) -> Option<crate::SurfaceCapabilities> {
|
) -> Option<crate::SurfaceCapabilities> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Adapter {
|
impl super::Adapter {
|
||||||
|
@ -230,6 +230,9 @@ impl super::Adapter {
|
|||||||
shader_model_support.HighestShaderModel >= d3d12::D3D_SHADER_MODEL_5_1,
|
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();
|
let base = wgt::Limits::default();
|
||||||
|
|
||||||
Some(crate::ExposedAdapter {
|
Some(crate::ExposedAdapter {
|
||||||
@ -238,6 +241,7 @@ impl super::Adapter {
|
|||||||
device,
|
device,
|
||||||
library: Arc::clone(library),
|
library: Arc::clone(library),
|
||||||
private_caps,
|
private_caps,
|
||||||
|
presentation_timer,
|
||||||
workarounds,
|
workarounds,
|
||||||
},
|
},
|
||||||
info,
|
info,
|
||||||
@ -541,4 +545,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||||||
composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque],
|
composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
|
||||||
|
wgt::PresentationTimestamp(self.presentation_timer.get_timestamp_ns())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,7 @@ pub struct Adapter {
|
|||||||
device: native::Device,
|
device: native::Device,
|
||||||
library: Arc<native::D3D12Lib>,
|
library: Arc<native::D3D12Lib>,
|
||||||
private_caps: PrivateCapabilities,
|
private_caps: PrivateCapabilities,
|
||||||
|
presentation_timer: auxil::dxgi::time::PresentationTimer,
|
||||||
//Note: this isn't used right now, but we'll need it later.
|
//Note: this isn't used right now, but we'll need it later.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
workarounds: Workarounds,
|
workarounds: Workarounds,
|
||||||
|
@ -93,6 +93,10 @@ impl crate::Adapter<Api> for Context {
|
|||||||
unsafe fn surface_capabilities(&self, surface: &Context) -> Option<crate::SurfaceCapabilities> {
|
unsafe fn surface_capabilities(&self, surface: &Context) -> Option<crate::SurfaceCapabilities> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
|
||||||
|
wgt::PresentationTimestamp::INVALID_TIMESTAMP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Queue<Api> for Context {
|
impl crate::Queue<Api> for Context {
|
||||||
|
@ -874,6 +874,10 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
|
||||||
|
wgt::PresentationTimestamp::INVALID_TIMESTAMP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::AdapterShared {
|
impl super::AdapterShared {
|
||||||
|
@ -242,6 +242,11 @@ pub trait Adapter<A: Api>: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// `None` means presentation is not supported for it.
|
/// `None` means presentation is not supported for it.
|
||||||
unsafe fn surface_capabilities(&self, surface: &A::Surface) -> Option<SurfaceCapabilities>;
|
unsafe fn surface_capabilities(&self, surface: &A::Surface) -> Option<SurfaceCapabilities>;
|
||||||
|
|
||||||
|
/// Creates a [`PresentationTimestamp`] using the adapter's WSI.
|
||||||
|
///
|
||||||
|
/// [`PresentationTimestamp`]: wgt::PresentationTimestamp
|
||||||
|
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Device<A: Api>: Send + Sync {
|
pub trait Device<A: Api>: Send + Sync {
|
||||||
|
@ -319,6 +319,12 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||||||
usage: crate::TextureUses::COLOR_TARGET | crate::TextureUses::COPY_DST, //TODO: expose more
|
usage: crate::TextureUses::COLOR_TARGET | crate::TextureUses::COPY_DST, //TODO: expose more
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
|
||||||
|
let timestamp = self.shared.presentation_timer.get_timestamp_ns();
|
||||||
|
|
||||||
|
wgt::PresentationTimestamp(timestamp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RESOURCE_HEAP_SUPPORT: &[MTLFeatureSet] = &[
|
const RESOURCE_HEAP_SUPPORT: &[MTLFeatureSet] = &[
|
||||||
|
@ -18,6 +18,7 @@ mod command;
|
|||||||
mod conv;
|
mod conv;
|
||||||
mod device;
|
mod device;
|
||||||
mod surface;
|
mod surface;
|
||||||
|
mod time;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt, iter, ops,
|
fmt, iter, ops,
|
||||||
@ -253,6 +254,7 @@ struct AdapterShared {
|
|||||||
disabilities: PrivateDisabilities,
|
disabilities: PrivateDisabilities,
|
||||||
private_caps: PrivateCapabilities,
|
private_caps: PrivateCapabilities,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
|
presentation_timer: time::PresentationTimer,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for AdapterShared {}
|
unsafe impl Send for AdapterShared {}
|
||||||
@ -268,6 +270,7 @@ impl AdapterShared {
|
|||||||
private_caps,
|
private_caps,
|
||||||
device: Mutex::new(device),
|
device: Mutex::new(device),
|
||||||
settings: Settings::default(),
|
settings: Settings::default(),
|
||||||
|
presentation_timer: time::PresentationTimer::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
wgpu-hal/src/metal/time.rs
Normal file
38
wgpu-hal/src/metal/time.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -1598,6 +1598,31 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||||||
composite_alpha_modes: conv::map_vk_composite_alpha(caps.supported_composite_alpha),
|
composite_alpha_modes: conv::map_vk_composite_alpha(caps.supported_composite_alpha),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// on mac, so this is fine.
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
let mut timespec = libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
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))]
|
||||||
|
{
|
||||||
|
wgt::PresentationTimestamp::INVALID_TIMESTAMP
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_format_16bit_norm_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
|
fn is_format_16bit_norm_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
|
||||||
|
@ -3965,6 +3965,43 @@ pub enum SurfaceStatus {
|
|||||||
Lost,
|
Lost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Nanosecond timestamp used by the presentation engine.
|
||||||
|
///
|
||||||
|
/// The specific clock depends on the window system integration (WSI) API used.
|
||||||
|
///
|
||||||
|
/// <table>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>WSI
|
||||||
|
/// <td>Clock
|
||||||
|
/// <tr>
|
||||||
|
/// <td>IDXGISwapchain
|
||||||
|
/// <td><a href="https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter">QueryPerformanceCounter</a>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>IPresentationManager
|
||||||
|
/// <td><a href="https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttimeprecise">QueryInterruptTimePrecise</a>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>CAMetalLayer
|
||||||
|
/// <td><a href="https://developer.apple.com/documentation/kernel/1462446-mach_absolute_time">mach_absolute_time</a>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>VK_GOOGLE_display_timing
|
||||||
|
/// <td><a href="https://linux.die.net/man/3/clock_gettime">clock_gettime(CLOCK_MONOTONIC)</a>
|
||||||
|
/// </table>
|
||||||
|
#[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.
|
/// RGBA double precision color.
|
||||||
///
|
///
|
||||||
/// This is not to be used as a generic color type, only for specific wgpu interfaces.
|
/// This is not to be used as a generic color type, only for specific wgpu interfaces.
|
||||||
|
@ -672,6 +672,18 @@ impl crate::Context for Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn adapter_get_presentation_timestamp(
|
||||||
|
&self,
|
||||||
|
adapter: &Self::AdapterId,
|
||||||
|
_adapter_data: &Self::AdapterData,
|
||||||
|
) -> wgt::PresentationTimestamp {
|
||||||
|
let global = &self.0;
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn surface_get_capabilities(
|
fn surface_get_capabilities(
|
||||||
&self,
|
&self,
|
||||||
surface: &Self::SurfaceId,
|
surface: &Self::SurfaceId,
|
||||||
|
@ -986,6 +986,14 @@ impl crate::context::Context for Context {
|
|||||||
format.describe().guaranteed_format_features
|
format.describe().guaranteed_format_features
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn adapter_get_presentation_timestamp(
|
||||||
|
&self,
|
||||||
|
_adapter: &Self::AdapterId,
|
||||||
|
_adapter_data: &Self::AdapterData,
|
||||||
|
) -> wgt::PresentationTimestamp {
|
||||||
|
wgt::PresentationTimestamp::INVALID_TIMESTAMP
|
||||||
|
}
|
||||||
|
|
||||||
fn surface_get_capabilities(
|
fn surface_get_capabilities(
|
||||||
&self,
|
&self,
|
||||||
_surface: &Self::SurfaceId,
|
_surface: &Self::SurfaceId,
|
||||||
|
@ -145,6 +145,11 @@ pub trait Context: Debug + Send + Sized + Sync {
|
|||||||
adapter_data: &Self::AdapterData,
|
adapter_data: &Self::AdapterData,
|
||||||
format: TextureFormat,
|
format: TextureFormat,
|
||||||
) -> TextureFormatFeatures;
|
) -> TextureFormatFeatures;
|
||||||
|
fn adapter_get_presentation_timestamp(
|
||||||
|
&self,
|
||||||
|
adapter: &Self::AdapterId,
|
||||||
|
adapter_data: &Self::AdapterData,
|
||||||
|
) -> wgt::PresentationTimestamp;
|
||||||
|
|
||||||
fn surface_get_capabilities(
|
fn surface_get_capabilities(
|
||||||
&self,
|
&self,
|
||||||
@ -1090,6 +1095,12 @@ pub(crate) trait DynContext: Debug + Send + Sync {
|
|||||||
adapter_data: &crate::Data,
|
adapter_data: &crate::Data,
|
||||||
format: TextureFormat,
|
format: TextureFormat,
|
||||||
) -> TextureFormatFeatures;
|
) -> TextureFormatFeatures;
|
||||||
|
fn adapter_get_presentation_timestamp(
|
||||||
|
&self,
|
||||||
|
adapter: &ObjectId,
|
||||||
|
adapter_data: &crate::Data,
|
||||||
|
) -> wgt::PresentationTimestamp;
|
||||||
|
|
||||||
fn surface_get_capabilities(
|
fn surface_get_capabilities(
|
||||||
&self,
|
&self,
|
||||||
surface: &ObjectId,
|
surface: &ObjectId,
|
||||||
@ -1969,6 +1980,15 @@ where
|
|||||||
let adapter_data = downcast_ref(adapter_data);
|
let adapter_data = downcast_ref(adapter_data);
|
||||||
Context::adapter_get_texture_format_features(self, &adapter, adapter_data, format)
|
Context::adapter_get_texture_format_features(self, &adapter, adapter_data, format)
|
||||||
}
|
}
|
||||||
|
fn adapter_get_presentation_timestamp(
|
||||||
|
&self,
|
||||||
|
adapter: &ObjectId,
|
||||||
|
adapter_data: &crate::Data,
|
||||||
|
) -> wgt::PresentationTimestamp {
|
||||||
|
let adapter = <T::AdapterId>::from(*adapter);
|
||||||
|
let adapter_data = downcast_ref(adapter_data);
|
||||||
|
Context::adapter_get_presentation_timestamp(self, &adapter, adapter_data)
|
||||||
|
}
|
||||||
|
|
||||||
fn surface_get_capabilities(
|
fn surface_get_capabilities(
|
||||||
&self,
|
&self,
|
||||||
|
Loading…
Reference in New Issue
Block a user