mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Allow disabling waiting for latency waitable object (#7400)
This commit is contained in:
parent
f04b3b020f
commit
e7cdfc436a
@ -73,7 +73,7 @@ By @Vecvec in [#7913](https://github.com/gfx-rs/wgpu/pull/7913).
|
||||
|
||||
#### DX12
|
||||
|
||||
- Fixed a bug where access to matrices with 2 rows would not work in some cases. By @andyleiserson in [#7438](https://github.com/gfx-rs/wgpu/pull/7438).
|
||||
- Allow disabling waiting for latency waitable object. By @marcpabst in [#7400](https://github.com/gfx-rs/wgpu/pull/7400)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@ -85,6 +85,11 @@ By @Vecvec in [#7913](https://github.com/gfx-rs/wgpu/pull/7913).
|
||||
|
||||
- Fix `STATUS_HEAP_CORRUPTION` crash when concurrently calling `create_sampler`. By @atlv24 in [#8043](https://github.com/gfx-rs/wgpu/pull/8043).
|
||||
|
||||
##### DX12
|
||||
|
||||
- Fixed a bug where access to matrices with 2 rows would not work in some cases. By @andyleiserson in [#7438](https://github.com/gfx-rs/wgpu/pull/7438).
|
||||
|
||||
|
||||
## v26.0.2 (2025-07-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@ -158,6 +158,7 @@ impl GPU {
|
||||
backend_options: wgpu_types::BackendOptions {
|
||||
dx12: wgpu_types::Dx12BackendOptions {
|
||||
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
|
||||
..Default::default()
|
||||
},
|
||||
gl: wgpu_types::GlBackendOptions::default(),
|
||||
noop: wgpu_types::NoopBackendOptions::default(),
|
||||
|
||||
@ -50,6 +50,7 @@ pub fn initialize_instance(backends: wgpu::Backends, params: &TestParameters) ->
|
||||
backend_options: wgpu::BackendOptions {
|
||||
dx12: wgpu::Dx12BackendOptions {
|
||||
shader_compiler: dx12_shader_compiler,
|
||||
..Default::default()
|
||||
},
|
||||
gl: wgpu::GlBackendOptions {
|
||||
fence_behavior: if cfg!(target_family = "wasm") {
|
||||
|
||||
@ -242,6 +242,7 @@ impl<A: hal::Api> Example<A> {
|
||||
backend_options: wgpu_types::BackendOptions {
|
||||
dx12: Dx12BackendOptions {
|
||||
shader_compiler: wgpu_types::Dx12Compiler::default_dynamic_dxc(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
@ -58,6 +58,7 @@ impl super::Adapter {
|
||||
instance_flags: wgt::InstanceFlags,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
compiler_container: Arc<shader_compilation::CompilerContainer>,
|
||||
backend_options: wgt::Dx12BackendOptions,
|
||||
) -> Option<crate::ExposedAdapter<super::Api>> {
|
||||
// Create the device so that we can get the capabilities.
|
||||
let device = {
|
||||
@ -534,6 +535,7 @@ impl super::Adapter {
|
||||
workarounds,
|
||||
memory_budget_thresholds,
|
||||
compiler_container,
|
||||
options: backend_options,
|
||||
},
|
||||
info,
|
||||
features,
|
||||
@ -697,6 +699,7 @@ impl crate::Adapter for super::Adapter {
|
||||
&self.library,
|
||||
self.memory_budget_thresholds,
|
||||
self.compiler_container.clone(),
|
||||
self.options.clone(),
|
||||
)?;
|
||||
Ok(crate::OpenDevice {
|
||||
device,
|
||||
|
||||
@ -48,6 +48,7 @@ impl super::Device {
|
||||
library: &Arc<D3D12Lib>,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
compiler_container: Arc<shader_compilation::CompilerContainer>,
|
||||
backend_options: wgt::Dx12BackendOptions,
|
||||
) -> Result<Self, crate::DeviceError> {
|
||||
if private_caps
|
||||
.instance_flags
|
||||
@ -198,6 +199,7 @@ impl super::Device {
|
||||
raw.clone(),
|
||||
Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
)),
|
||||
options: backend_options,
|
||||
library: Arc::clone(library),
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: Default::default(),
|
||||
|
||||
@ -109,6 +109,7 @@ impl crate::Instance for super::Instance {
|
||||
flags: desc.flags,
|
||||
memory_budget_thresholds: desc.memory_budget_thresholds,
|
||||
compiler_container: Arc::new(compiler_container),
|
||||
options: desc.backend_options.dx12.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -125,6 +126,7 @@ impl crate::Instance for super::Instance {
|
||||
target: SurfaceTarget::WndHandle(Foundation::HWND(handle.hwnd.get() as *mut _)),
|
||||
supports_allow_tearing: self.supports_allow_tearing,
|
||||
swap_chain: RwLock::new(None),
|
||||
options: self.options.clone(),
|
||||
}),
|
||||
_ => Err(crate::InstanceError::new(format!(
|
||||
"window handle {window_handle:?} is not a Win32 handle"
|
||||
@ -147,6 +149,7 @@ impl crate::Instance for super::Instance {
|
||||
self.flags,
|
||||
self.memory_budget_thresholds,
|
||||
self.compiler_container.clone(),
|
||||
self.options.clone(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
||||
@ -464,6 +464,7 @@ pub struct Instance {
|
||||
flags: wgt::InstanceFlags,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
compiler_container: Arc<shader_compilation::CompilerContainer>,
|
||||
options: wgt::Dx12BackendOptions,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
@ -481,6 +482,7 @@ impl Instance {
|
||||
target: SurfaceTarget::Visual(visual.to_owned()),
|
||||
supports_allow_tearing: self.supports_allow_tearing,
|
||||
swap_chain: RwLock::new(None),
|
||||
options: self.options.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -498,6 +500,7 @@ impl Instance {
|
||||
target: SurfaceTarget::SurfaceHandle(surface_handle),
|
||||
supports_allow_tearing: self.supports_allow_tearing,
|
||||
swap_chain: RwLock::new(None),
|
||||
options: self.options.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,6 +517,7 @@ impl Instance {
|
||||
target: SurfaceTarget::SwapChainPanel(swap_chain_panel.to_owned()),
|
||||
supports_allow_tearing: self.supports_allow_tearing,
|
||||
swap_chain: RwLock::new(None),
|
||||
options: self.options.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -528,7 +532,7 @@ struct SwapChain {
|
||||
// when the swapchain is destroyed
|
||||
resources: Vec<Direct3D12::ID3D12Resource>,
|
||||
/// Handle is freed in [`Self::release_resources()`]
|
||||
waitable: Foundation::HANDLE,
|
||||
waitable: Option<Foundation::HANDLE>,
|
||||
acquired_count: usize,
|
||||
present_mode: wgt::PresentMode,
|
||||
format: wgt::TextureFormat,
|
||||
@ -550,6 +554,7 @@ pub struct Surface {
|
||||
target: SurfaceTarget,
|
||||
supports_allow_tearing: bool,
|
||||
swap_chain: RwLock<Option<SwapChain>>,
|
||||
options: wgt::Dx12BackendOptions,
|
||||
}
|
||||
|
||||
unsafe impl Send for Surface {}
|
||||
@ -559,6 +564,12 @@ impl Surface {
|
||||
pub fn swap_chain(&self) -> Option<Dxgi::IDXGISwapChain3> {
|
||||
Some(self.swap_chain.read().as_ref()?.raw.clone())
|
||||
}
|
||||
|
||||
/// Returns the waitable handle associated with this swap chain, if any.
|
||||
/// Handle is only valid while the swap chain is alive.
|
||||
pub unsafe fn waitable_handle(&self) -> Option<Foundation::HANDLE> {
|
||||
self.swap_chain.read().as_ref()?.waitable
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@ -601,6 +612,7 @@ pub struct Adapter {
|
||||
workarounds: Workarounds,
|
||||
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
|
||||
compiler_container: Arc<shader_compilation::CompilerContainer>,
|
||||
options: wgt::Dx12BackendOptions,
|
||||
}
|
||||
|
||||
unsafe impl Send for Adapter {}
|
||||
@ -659,6 +671,7 @@ pub struct Device {
|
||||
idler: Idler,
|
||||
features: wgt::Features,
|
||||
shared: Arc<DeviceShared>,
|
||||
options: wgt::Dx12BackendOptions,
|
||||
// CPU only pools
|
||||
rtv_pool: Arc<Mutex<descriptor::CpuPool>>,
|
||||
dsv_pool: Mutex<descriptor::CpuPool>,
|
||||
@ -1178,7 +1191,9 @@ impl crate::DynAccelerationStructure for AccelerationStructure {}
|
||||
|
||||
impl SwapChain {
|
||||
unsafe fn release_resources(mut self) -> Dxgi::IDXGISwapChain3 {
|
||||
unsafe { Foundation::HANDLE::free(&mut self.waitable) };
|
||||
if let Some(mut waitable) = self.waitable.take() {
|
||||
unsafe { Foundation::HANDLE::free(&mut waitable) };
|
||||
}
|
||||
self.raw
|
||||
}
|
||||
|
||||
@ -1190,14 +1205,21 @@ impl SwapChain {
|
||||
Some(duration) => duration.as_millis() as u32,
|
||||
None => Threading::INFINITE,
|
||||
};
|
||||
match unsafe { Threading::WaitForSingleObject(self.waitable, timeout_ms) } {
|
||||
Foundation::WAIT_ABANDONED | Foundation::WAIT_FAILED => Err(crate::SurfaceError::Lost),
|
||||
Foundation::WAIT_OBJECT_0 => Ok(true),
|
||||
Foundation::WAIT_TIMEOUT => Ok(false),
|
||||
other => {
|
||||
log::error!("Unexpected wait status: 0x{other:x?}");
|
||||
Err(crate::SurfaceError::Lost)
|
||||
|
||||
if let Some(waitable) = self.waitable {
|
||||
match unsafe { Threading::WaitForSingleObject(waitable, timeout_ms) } {
|
||||
Foundation::WAIT_ABANDONED | Foundation::WAIT_FAILED => {
|
||||
Err(crate::SurfaceError::Lost)
|
||||
}
|
||||
Foundation::WAIT_OBJECT_0 => Ok(true),
|
||||
Foundation::WAIT_TIMEOUT => Ok(false),
|
||||
other => {
|
||||
log::error!("Unexpected wait status: 0x{other:x?}");
|
||||
Err(crate::SurfaceError::Lost)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1365,7 +1387,14 @@ impl crate::Surface for Surface {
|
||||
|
||||
unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) }
|
||||
.into_device_result("SetMaximumFrameLatency")?;
|
||||
let waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() };
|
||||
|
||||
let waitable = match device.options.latency_waitable_object {
|
||||
wgt::Dx12UseFrameLatencyWaitableObject::None => None,
|
||||
wgt::Dx12UseFrameLatencyWaitableObject::Wait
|
||||
| wgt::Dx12UseFrameLatencyWaitableObject::DontWait => {
|
||||
Some(unsafe { swap_chain.GetFrameLatencyWaitableObject() })
|
||||
}
|
||||
};
|
||||
|
||||
let mut resources = Vec::with_capacity(swap_chain_buffer as usize);
|
||||
for i in 0..swap_chain_buffer {
|
||||
@ -1412,7 +1441,13 @@ impl crate::Surface for Surface {
|
||||
let mut swapchain = self.swap_chain.write();
|
||||
let sc = swapchain.as_mut().unwrap();
|
||||
|
||||
unsafe { sc.wait(timeout) }?;
|
||||
match self.options.latency_waitable_object {
|
||||
wgt::Dx12UseFrameLatencyWaitableObject::None
|
||||
| wgt::Dx12UseFrameLatencyWaitableObject::DontWait => {}
|
||||
wgt::Dx12UseFrameLatencyWaitableObject::Wait => {
|
||||
unsafe { sc.wait(timeout) }?;
|
||||
}
|
||||
}
|
||||
|
||||
let base_index = unsafe { sc.raw.GetCurrentBackBufferIndex() } as usize;
|
||||
let index = (base_index + sc.acquired_count) % sc.resources.len();
|
||||
|
||||
@ -359,6 +359,8 @@ impl GlBackendOptions {
|
||||
pub struct Dx12BackendOptions {
|
||||
/// Which DX12 shader compiler to use.
|
||||
pub shader_compiler: Dx12Compiler,
|
||||
/// Whether to wait for the latency waitable object before acquiring the next swapchain image.
|
||||
pub latency_waitable_object: Dx12UseFrameLatencyWaitableObject,
|
||||
}
|
||||
|
||||
impl Dx12BackendOptions {
|
||||
@ -368,8 +370,11 @@ impl Dx12BackendOptions {
|
||||
#[must_use]
|
||||
pub fn from_env_or_default() -> Self {
|
||||
let compiler = Dx12Compiler::from_env().unwrap_or_default();
|
||||
let latency_waitable_object =
|
||||
Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();
|
||||
Self {
|
||||
shader_compiler: compiler,
|
||||
latency_waitable_object,
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,7 +384,12 @@ impl Dx12BackendOptions {
|
||||
#[must_use]
|
||||
pub fn with_env(self) -> Self {
|
||||
let shader_compiler = self.shader_compiler.with_env();
|
||||
Self { shader_compiler }
|
||||
let latency_waitable_object = self.latency_waitable_object.with_env();
|
||||
|
||||
Self {
|
||||
shader_compiler,
|
||||
latency_waitable_object,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -515,6 +525,54 @@ impl Dx12Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether and how to use a waitable handle obtained from `GetFrameLatencyWaitableObject`.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub enum Dx12UseFrameLatencyWaitableObject {
|
||||
/// Do not obtain a waitable handle and do not wait for it. The swapchain will
|
||||
/// be created without the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag.
|
||||
None,
|
||||
/// Obtain a waitable handle and wait for it before acquiring the next swapchain image.
|
||||
#[default]
|
||||
Wait,
|
||||
/// Create the swapchain with the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag and
|
||||
/// obtain a waitable handle, but do not wait for it before acquiring the next swapchain image.
|
||||
/// This is useful if the application wants to wait for the waitable object itself.
|
||||
DontWait,
|
||||
}
|
||||
|
||||
impl Dx12UseFrameLatencyWaitableObject {
|
||||
/// Choose whether to use a frame latency waitable object from the environment variable `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT`.
|
||||
///
|
||||
/// Valid values, case insensitive:
|
||||
/// - `None`
|
||||
/// - `Wait`
|
||||
/// - `DontWait`
|
||||
#[must_use]
|
||||
pub fn from_env() -> Option<Self> {
|
||||
let value = crate::env::var("WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT")
|
||||
.as_deref()?
|
||||
.to_lowercase();
|
||||
match value.as_str() {
|
||||
"none" => Some(Self::None),
|
||||
"wait" => Some(Self::Wait),
|
||||
"dontwait" => Some(Self::DontWait),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes the given setting, modifies it based on the `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT` environment variable, and returns the result.
|
||||
///
|
||||
/// See `from_env` for more information.
|
||||
#[must_use]
|
||||
pub fn with_env(self) -> Self {
|
||||
if let Some(compiler) = Self::from_env() {
|
||||
compiler
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Selects which OpenGL ES 3 minor version to request.
|
||||
///
|
||||
/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user