Skip to content

Commit 00ea850

Browse files
authored
Allow timeouting on poll (#8282)
1 parent 06fc6f7 commit 00ea850

File tree

17 files changed

+117
-38
lines changed

17 files changed

+117
-38
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162).
165165
- Added mesh shader support to `wgpu`, with examples. Requires passthrough. By @SupaMaggie70Incorporated in [#7345](https://github.com/gfx-rs/wgpu/pull/7345).
166166

167167
- Added support for external textures based on WebGPU's [`GPUExternalTexture`](https://www.w3.org/TR/webgpu/#gpuexternaltexture). These allow shaders to transparently operate on potentially multiplanar source texture data in either RGB or YCbCr formats via WGSL's `texture_external` type. This is gated behind the `Features::EXTERNAL_TEXTURE` feature, which is currently only supported on DX12. By @jamienicol in [#4386](https://github.com/gfx-rs/wgpu/issues/4386).
168+
- `wgpu::Device::poll` can now specify a timeout via `wgpu::PollType::WaitWithTimeout`/`wgpu::PollType::WaitForSubmissionIndexWithTimeout`. By @wumpf in [#8282](https://github.com/gfx-rs/wgpu/pull/8282)
168169

169170
#### naga
170171

@@ -194,6 +195,7 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162).
194195
- Require new `F16_IN_F32` downlevel flag for `quantizeToF16`, `pack2x16float`, and `unpack2x16float` in WGSL input. By @aleiserson in [#8130](https://github.com/gfx-rs/wgpu/pull/8130).
195196
- The error message for non-copyable depth/stencil formats no longer mentions the aspect when it is not relevant. By @reima in [#8156](https://github.com/gfx-rs/wgpu/pull/8156).
196197
- Track the initialization status of buffer memory correctly when `copy_texture_to_buffer` skips over padding space between rows or layers, or when the start/end of a texture-buffer transfer is not 4B aligned. By @andyleiserson in [#8099](https://github.com/gfx-rs/wgpu/pull/8099).
198+
- `wgpu::PollType::Wait`/`wgpu::PollType::WaitForSubmissionIndex` will no longer timeout after 60 seconds, but instead wait indefinitely or (depending on backend implementation) until an error is encountered. Use `wgpu::PollType::WaitWithTimeout`/`wgpu::PollType::WaitForSubmissionIndexWithTimeout` if you need a timeout. By @wumpf in [#8282](https://github.com/gfx-rs/wgpu/pull/8282)
197199

198200
#### naga
199201

tests/tests/wgpu-gpu/poll.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::num::NonZeroU64;
1+
use std::{num::NonZeroU64, time::Duration};
22

33
use wgpu::{
44
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
@@ -13,8 +13,10 @@ use wgpu_test::{
1313
pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
1414
vec.extend([
1515
WAIT,
16+
WAIT_WITH_TIMEOUT,
1617
DOUBLE_WAIT,
1718
WAIT_ON_SUBMISSION,
19+
WAIT_ON_SUBMISSION_WITH_TIMEOUT,
1820
DOUBLE_WAIT_ON_SUBMISSION,
1921
WAIT_OUT_OF_ORDER,
2022
WAIT_AFTER_BAD_SUBMISSION,
@@ -75,6 +77,18 @@ static WAIT: GpuTestConfiguration = GpuTestConfiguration::new()
7577
ctx.async_poll(PollType::wait()).await.unwrap();
7678
});
7779

80+
#[gpu_test]
81+
static WAIT_WITH_TIMEOUT: GpuTestConfiguration = GpuTestConfiguration::new()
82+
.parameters(TestParameters::default().enable_noop())
83+
.run_async(|ctx| async move {
84+
let cmd_buf = generate_dummy_work(&ctx);
85+
86+
ctx.queue.submit(Some(cmd_buf));
87+
ctx.async_poll(PollType::WaitWithTimeout(Duration::from_secs(1)))
88+
.await
89+
.unwrap();
90+
});
91+
7892
#[gpu_test]
7993
static DOUBLE_WAIT: GpuTestConfiguration = GpuTestConfiguration::new()
8094
.parameters(TestParameters::default().enable_noop())
@@ -96,6 +110,21 @@ static WAIT_ON_SUBMISSION: GpuTestConfiguration = GpuTestConfiguration::new()
96110
ctx.async_poll(PollType::wait_for(index)).await.unwrap();
97111
});
98112

113+
#[gpu_test]
114+
static WAIT_ON_SUBMISSION_WITH_TIMEOUT: GpuTestConfiguration = GpuTestConfiguration::new()
115+
.parameters(TestParameters::default().enable_noop())
116+
.run_async(|ctx| async move {
117+
let cmd_buf = generate_dummy_work(&ctx);
118+
119+
let index = ctx.queue.submit(Some(cmd_buf));
120+
ctx.async_poll(PollType::WaitForSubmissionIndexWithTimeout {
121+
submission_index: index,
122+
timeout: Duration::from_secs(1),
123+
})
124+
.await
125+
.unwrap();
126+
});
127+
99128
#[gpu_test]
100129
static DOUBLE_WAIT_ON_SUBMISSION: GpuTestConfiguration = GpuTestConfiguration::new()
101130
.parameters(TestParameters::default().enable_noop())

wgpu-core/src/device/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ pub const SHADER_STAGE_COUNT: usize = hal::MAX_CONCURRENT_SHADER_STAGES;
3535
// value is enough for a 16k texture with float4 format.
3636
pub(crate) const ZERO_BUFFER_SIZE: BufferAddress = 512 << 10;
3737

38-
// If a submission is not completed within this time, we go off into UB land.
39-
// See https://github.com/gfx-rs/wgpu/issues/4589. 60s to reduce the chances of this.
40-
const CLEANUP_WAIT_MS: u32 = 60000;
41-
4238
pub(crate) const ENTRYPOINT_FAILURE_ERROR: &str = "The given EntryPoint is Invalid";
4339

4440
pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;

wgpu-core/src/device/queue.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ impl Drop for Queue {
183183
fence.as_ref(),
184184
last_successful_submission_index,
185185
#[cfg(not(target_arch = "wasm32"))]
186-
timeout_ms,
186+
Some(core::time::Duration::from_millis(timeout_ms)),
187187
#[cfg(target_arch = "wasm32")]
188-
0, // WebKit and Chromium don't support a non-0 timeout
188+
Some(core::time::Duration::ZERO), // WebKit and Chromium don't support a non-0 timeout
189189
)
190190
};
191191
// Note: If we don't panic below we are in UB land (destroying resources while they are still in use by the GPU).

wgpu-core/src/device/resource.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use crate::{
2929
device::{
3030
bgl, create_validator, life::WaitIdleError, map_buffer, AttachmentData,
3131
DeviceLostInvocation, HostMap, MissingDownlevelFlags, MissingFeatures, RenderPassContext,
32-
CLEANUP_WAIT_MS,
3332
},
3433
hal_label,
3534
init_tracker::{
@@ -712,7 +711,10 @@ impl Device {
712711

713712
// If a wait was requested, determine which submission index to wait for.
714713
let wait_submission_index = match poll_type {
715-
wgt::PollType::WaitForSubmissionIndex(submission_index) => {
714+
wgt::PollType::WaitForSubmissionIndex(submission_index)
715+
| wgt::PollType::WaitForSubmissionIndexWithTimeout {
716+
submission_index, ..
717+
} => {
716718
let last_successful_submission_index = self
717719
.last_successful_submission_index
718720
.load(Ordering::Acquire);
@@ -728,7 +730,7 @@ impl Device {
728730

729731
Some(submission_index)
730732
}
731-
wgt::PollType::Wait => Some(
733+
wgt::PollType::Wait | wgt::PollType::WaitWithTimeout { .. } => Some(
732734
self.last_successful_submission_index
733735
.load(Ordering::Acquire),
734736
),
@@ -741,7 +743,7 @@ impl Device {
741743

742744
let wait_result = unsafe {
743745
self.raw()
744-
.wait(fence.as_ref(), target_submission_index, CLEANUP_WAIT_MS)
746+
.wait(fence.as_ref(), target_submission_index, poll_type.timeout())
745747
};
746748

747749
// This error match is only about `DeviceErrors`. At this stage we do not care if
@@ -4499,7 +4501,7 @@ impl Device {
44994501
let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref()) }
45004502
.map_err(|e| self.handle_hal_error(e))?;
45014503
if last_done_index < submission_index {
4502-
unsafe { self.raw().wait(fence.as_ref(), submission_index, !0) }
4504+
unsafe { self.raw().wait(fence.as_ref(), submission_index, None) }
45034505
.map_err(|e| self.handle_hal_error(e))?;
45044506
drop(fence);
45054507
if let Some(queue) = self.get_queue() {

wgpu-hal/examples/halmark/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct ExecutionContext<A: hal::Api> {
5454

5555
impl<A: hal::Api> ExecutionContext<A> {
5656
unsafe fn wait_and_clear(&mut self, device: &A::Device) {
57-
device.wait(&self.fence, self.fence_value, !0).unwrap();
57+
device.wait(&self.fence, self.fence_value, None).unwrap();
5858
self.encoder.reset_all(self.used_cmd_bufs.drain(..));
5959
for view in self.used_views.drain(..) {
6060
device.destroy_texture_view(view);
@@ -519,7 +519,7 @@ impl<A: hal::Api> Example<A> {
519519
queue
520520
.submit(&[&init_cmd], &[], (&mut fence, init_fence_value))
521521
.unwrap();
522-
device.wait(&fence, init_fence_value, !0).unwrap();
522+
device.wait(&fence, init_fence_value, None).unwrap();
523523
device.destroy_buffer(staging_buffer);
524524
cmd_encoder.reset_all(iter::once(init_cmd));
525525
fence

wgpu-hal/examples/ray-traced-triangle/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ struct ExecutionContext<A: hal::Api> {
181181

182182
impl<A: hal::Api> ExecutionContext<A> {
183183
unsafe fn wait_and_clear(&mut self, device: &A::Device) {
184-
device.wait(&self.fence, self.fence_value, !0).unwrap();
184+
device.wait(&self.fence, self.fence_value, None).unwrap();
185185
self.encoder.reset_all(self.used_cmd_bufs.drain(..));
186186
for view in self.used_views.drain(..) {
187187
device.destroy_texture_view(view);
@@ -816,7 +816,7 @@ impl<A: hal::Api> Example<A> {
816816
queue
817817
.submit(&[&init_cmd], &[], (&mut fence, init_fence_value))
818818
.unwrap();
819-
device.wait(&fence, init_fence_value, !0).unwrap();
819+
device.wait(&fence, init_fence_value, None).unwrap();
820820
cmd_encoder.reset_all(iter::once(init_cmd));
821821
fence
822822
};

wgpu-hal/src/dx12/device.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,9 +2237,9 @@ impl crate::Device for super::Device {
22372237
&self,
22382238
fence: &super::Fence,
22392239
value: crate::FenceValue,
2240-
timeout_ms: u32,
2240+
timeout: Option<Duration>,
22412241
) -> Result<bool, crate::DeviceError> {
2242-
let timeout_duration = Duration::from_millis(timeout_ms as u64);
2242+
let timeout = timeout.unwrap_or(Duration::MAX);
22432243

22442244
// We first check if the fence has already reached the value we're waiting for.
22452245
let mut fence_value = unsafe { fence.raw.GetCompletedValue() };
@@ -2273,7 +2273,7 @@ impl crate::Device for super::Device {
22732273
//
22742274
// This happens when a previous iteration WaitForSingleObject succeeded with a previous fence value,
22752275
// right before the timeout would have been hit.
2276-
let remaining_wait_duration = match timeout_duration.checked_sub(elapsed) {
2276+
let remaining_wait_duration = match timeout.checked_sub(elapsed) {
22772277
Some(remaining) => remaining,
22782278
None => {
22792279
log::trace!("Timeout elapsed in between waits!");
@@ -2286,7 +2286,7 @@ impl crate::Device for super::Device {
22862286
match unsafe {
22872287
Threading::WaitForSingleObject(
22882288
event.0,
2289-
remaining_wait_duration.as_millis().try_into().unwrap(),
2289+
remaining_wait_duration.as_millis().min(u32::MAX as u128) as u32,
22902290
)
22912291
} {
22922292
Foundation::WAIT_OBJECT_0 => {}

wgpu-hal/src/dynamic/device.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ pub trait DynDevice: DynResource {
135135
&self,
136136
fence: &dyn DynFence,
137137
value: FenceValue,
138-
timeout_ms: u32,
138+
timeout: Option<core::time::Duration>,
139139
) -> Result<bool, DeviceError>;
140140

141141
unsafe fn start_graphics_debugger_capture(&self) -> bool;
@@ -486,10 +486,10 @@ impl<D: Device + DynResource> DynDevice for D {
486486
&self,
487487
fence: &dyn DynFence,
488488
value: FenceValue,
489-
timeout_ms: u32,
489+
timeout: Option<core::time::Duration>,
490490
) -> Result<bool, DeviceError> {
491491
let fence = fence.expect_downcast_ref();
492-
unsafe { D::wait(self, fence, value, timeout_ms) }
492+
unsafe { D::wait(self, fence, value, timeout) }
493493
}
494494

495495
unsafe fn start_graphics_debugger_capture(&self) -> bool {

wgpu-hal/src/gles/device.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ impl crate::Device for super::Device {
15641564
&self,
15651565
fence: &super::Fence,
15661566
wait_value: crate::FenceValue,
1567-
timeout_ms: u32,
1567+
timeout: Option<core::time::Duration>,
15681568
) -> Result<bool, crate::DeviceError> {
15691569
if fence.satisfied(wait_value) {
15701570
return Ok(true);
@@ -1578,7 +1578,9 @@ impl crate::Device for super::Device {
15781578
let timeout_ns = if cfg!(any(webgl, Emscripten)) {
15791579
0
15801580
} else {
1581-
(timeout_ms as u64 * 1_000_000).min(!0u32 as u64)
1581+
timeout
1582+
.map(|t| t.as_nanos().min(u32::MAX as u128) as u32)
1583+
.unwrap_or(u32::MAX)
15821584
};
15831585
fence.wait(gl, wait_value, timeout_ns)
15841586
}

0 commit comments

Comments
 (0)