Skip to content

Commit 0a4a214

Browse files
authored
Merge branch 'trunk' into timestamp-in-encoders-feature
2 parents a32d198 + 84ba4e5 commit 0a4a214

File tree

20 files changed

+289
-114
lines changed

20 files changed

+289
-114
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,18 @@ jobs:
9292

9393
# MacOS
9494
- name: MacOS x86_64
95-
os: macos-12
95+
os: macos-14
9696
target: x86_64-apple-darwin
9797
kind: native
9898

9999
- name: MacOS aarch64
100-
os: macos-12
100+
os: macos-14
101101
target: aarch64-apple-darwin
102102
kind: native
103103

104104
# IOS
105105
- name: IOS aarch64
106-
os: macos-12
106+
os: macos-14
107107
target: aarch64-apple-ios
108108
kind: native
109109

@@ -249,7 +249,7 @@ jobs:
249249

250250
# MacOS
251251
- name: MacOS x86_64
252-
os: macos-12
252+
os: macos-14
253253
target: x86_64-apple-darwin
254254

255255
# Linux
@@ -383,7 +383,7 @@ jobs:
383383

384384
# Mac
385385
- name: Mac aarch64
386-
os: macos-13-xlarge
386+
os: macos-14
387387

388388
# Linux
389389
- name: Linux x86_64

.github/workflows/shaders.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
6363
naga-validate-macos:
6464
name: "Validate: MSL"
65-
runs-on: macos-latest
65+
runs-on: macos-14
6666
steps:
6767
- uses: actions/checkout@v4
6868

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,26 @@ Bottom level categories:
9292
- `wgpu::CommandEncoder::write_timestamp` requires now the new `wgpu::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS` feature which is available
9393
on all native backends but not on WebGPU (due to a spec change `write_timestamp` is no longer supported on WebGPU).
9494
By @wumpf in [#5188](https://github.com/gfx-rs/wgpu/pull/5188)
95+
- Added `InstanceFlags::GPU_BASED_VALIDATION`, which enables GPU-based validation for shaders. This is currently only supported on the DX12 back end; other platforms ignore this flag, for now.
96+
- This has been added to the set of flags set by `InstanceFlags::debugging` and `InstanceFlags::from_build_config`. If you notice your graphics workloads running more slowly, this may be the culprit.
97+
- As with other instance flags, this flag can be changed in calls to `InstanceFlags::with_env` with the new `WGPU_GPU_BASED_VALIDATION` environment variable.
98+
99+
By @ErichDonGubler in [#5046](https://github.com/gfx-rs/wgpu/pull/5046).
100+
- `wgpu::Instance` can now report which `wgpu::Backends` are available based on the build configuration. By @wumpf [#5167](https://github.com/gfx-rs/wgpu/pull/5167)
101+
```diff
102+
-wgpu::Instance::any_backend_feature_enabled()
103+
+!wgpu::Instance::enabled_backend_features().is_empty()
104+
```
105+
- `wgpu::Id` now implements `PartialOrd`/`Ord` allowing it to be put in `BTreeMap`s. By @cwfitzgerald and @9291Sam in [#5176](https://github.com/gfx-rs/wgpu/pull/5176)
95106

96107
### Bug Fixes
97108

98109
#### General
99110
- Fix `panic!` when dropping `Instance` without `InstanceFlags::VALIDATION`. By @hakolao in [#5134](https://github.com/gfx-rs/wgpu/pull/5134)
100111
- Fix `serde` feature not compiling for `wgpu-types`. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149)
101112
- Fix the validation of vertex and index ranges. By @nical in [#5144](https://github.com/gfx-rs/wgpu/pull/5144) and [#5156](https://github.com/gfx-rs/wgpu/pull/5156)
113+
- Device lost callbacks are invoked when replaced and when global is dropped. By @bradwerth in [#5168](https://github.com/gfx-rs/wgpu/pull/5168)
114+
- Fix panic when creating a surface while no backend is available. By @wumpf [#5166](https://github.com/gfx-rs/wgpu/pull/5166)
102115

103116
#### WGL
104117

d3d12/src/debug.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use crate::com::ComPtr;
2-
use winapi::um::d3d12sdklayers;
32
#[cfg(any(feature = "libloading", feature = "implicit-link"))]
43
use winapi::Interface as _;
4+
use winapi::{
5+
shared::{minwindef::TRUE, winerror::S_OK},
6+
um::d3d12sdklayers,
7+
};
58

69
pub type Debug = ComPtr<d3d12sdklayers::ID3D12Debug>;
710

@@ -40,4 +43,14 @@ impl Debug {
4043
pub fn enable_layer(&self) {
4144
unsafe { self.EnableDebugLayer() }
4245
}
46+
47+
pub fn enable_gpu_based_validation(&self) -> bool {
48+
let (ptr, hr) = unsafe { self.cast::<d3d12sdklayers::ID3D12Debug1>() };
49+
if hr == S_OK {
50+
unsafe { ptr.SetEnableGPUBasedValidation(TRUE) };
51+
true
52+
} else {
53+
false
54+
}
55+
}
4356
}

tests/src/image.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ pub async fn compare_image_output(
183183
let file_stem = reference_path.file_stem().unwrap().to_string_lossy();
184184
let renderer = format!(
185185
"{}-{}-{}",
186-
adapter_info.backend.to_str(),
186+
adapter_info.backend,
187187
sanitize_for_path(&adapter_info.name),
188188
sanitize_for_path(&adapter_info.driver)
189189
);

tests/tests/device.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,3 +549,69 @@ static DEVICE_DROP_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new()
549549
"Device lost callback should have been called."
550550
);
551551
});
552+
553+
#[gpu_test]
554+
static DEVICE_LOST_REPLACED_CALLBACK: GpuTestConfiguration = GpuTestConfiguration::new()
555+
.parameters(TestParameters::default())
556+
.run_sync(|ctx| {
557+
// This test checks that a device_lost_callback is called when it is
558+
// replaced by another callback.
559+
let was_called = std::sync::Arc::<std::sync::atomic::AtomicBool>::new(false.into());
560+
561+
// Set a LoseDeviceCallback on the device.
562+
let was_called_clone = was_called.clone();
563+
let callback = Box::new(move |reason, _m| {
564+
was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst);
565+
assert!(
566+
matches!(reason, wgt::DeviceLostReason::ReplacedCallback),
567+
"Device lost info reason should match DeviceLostReason::ReplacedCallback."
568+
);
569+
});
570+
ctx.device.set_device_lost_callback(callback);
571+
572+
// Replace the callback.
573+
let replacement_callback = Box::new(move |_r, _m| {});
574+
ctx.device.set_device_lost_callback(replacement_callback);
575+
576+
assert!(
577+
was_called.load(std::sync::atomic::Ordering::SeqCst),
578+
"Device lost callback should have been called."
579+
);
580+
});
581+
582+
#[gpu_test]
583+
static DROPPED_GLOBAL_THEN_DEVICE_LOST: GpuTestConfiguration = GpuTestConfiguration::new()
584+
.parameters(TestParameters::default().skip(FailureCase::always()))
585+
.run_sync(|ctx| {
586+
// What we want to do is to drop the Global, forcing a code path that
587+
// eventually calls Device.prepare_to_die, without having first dropped
588+
// the device. This models what might happen in a user agent that kills
589+
// wgpu without providing a more orderly shutdown. In such a case, the
590+
// device lost callback should be invoked with the message "Device is
591+
// dying."
592+
let was_called = std::sync::Arc::<std::sync::atomic::AtomicBool>::new(false.into());
593+
594+
// Set a LoseDeviceCallback on the device.
595+
let was_called_clone = was_called.clone();
596+
let callback = Box::new(move |reason, message| {
597+
was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst);
598+
assert!(
599+
matches!(reason, wgt::DeviceLostReason::Dropped),
600+
"Device lost info reason should match DeviceLostReason::Dropped."
601+
);
602+
assert!(
603+
message == "Device is dying.",
604+
"Device lost info message is \"{}\" and it should be \"Device is dying.\".",
605+
message
606+
);
607+
});
608+
ctx.device.set_device_lost_callback(callback);
609+
610+
// TODO: Drop the Global, somehow.
611+
612+
// Confirm that the callback was invoked.
613+
assert!(
614+
was_called.load(std::sync::atomic::Ordering::SeqCst),
615+
"Device lost callback should have been called."
616+
);
617+
});

wgpu-core/src/device/global.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ impl Global {
645645
RwLock::new(TextureInitTracker::new(desc.mip_level_count, 0));
646646

647647
let (id, resource) = fid.assign(texture);
648-
api_log!("Device::create_texture -> {id:?}");
648+
api_log!("Device::create_texture({desc:?}) -> {id:?}");
649649

650650
device.trackers.lock().textures.insert_single(
651651
id,
@@ -2266,8 +2266,8 @@ impl Global {
22662266
}
22672267
}
22682268

2269-
// This closure will be called exactly once during "lose the device"
2270-
// or when the device is dropped, if it was never lost.
2269+
// This closure will be called exactly once during "lose the device",
2270+
// or when it is replaced.
22712271
pub fn device_set_device_lost_closure<A: HalApi>(
22722272
&self,
22732273
device_id: DeviceId,
@@ -2277,6 +2277,12 @@ impl Global {
22772277

22782278
if let Ok(device) = hub.devices.get(device_id) {
22792279
let mut life_tracker = device.lock_life();
2280+
if let Some(existing_closure) = life_tracker.device_lost_closure.take() {
2281+
// It's important to not hold the lock while calling the closure.
2282+
drop(life_tracker);
2283+
existing_closure.call(DeviceLostReason::ReplacedCallback, "".to_string());
2284+
life_tracker = device.lock_life();
2285+
}
22802286
life_tracker.device_lost_closure = Some(device_lost_closure);
22812287
}
22822288
}
@@ -2333,7 +2339,7 @@ impl Global {
23332339
range: Range<BufferAddress>,
23342340
op: BufferMapOperation,
23352341
) -> BufferAccessResult {
2336-
api_log!("Buffer::map_async {buffer_id:?}");
2342+
api_log!("Buffer::map_async {buffer_id:?} range {range:?} op: {op:?}");
23372343

23382344
// User callbacks must not be called while holding buffer_map_async_inner's locks, so we
23392345
// defer the error callback if it needs to be called immediately (typically when running
@@ -2460,7 +2466,7 @@ impl Global {
24602466
size: Option<BufferAddress>,
24612467
) -> Result<(*mut u8, u64), BufferAccessError> {
24622468
profiling::scope!("Buffer::get_mapped_range");
2463-
api_log!("Buffer::get_mapped_range {buffer_id:?}");
2469+
api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}");
24642470

24652471
let hub = A::hub(self);
24662472

wgpu-core/src/device/resource.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3433,6 +3433,11 @@ impl<A: HalApi> Device<A> {
34333433
current_index,
34343434
self.command_allocator.lock().as_mut().unwrap(),
34353435
);
3436+
if let Some(device_lost_closure) = life_tracker.device_lost_closure.take() {
3437+
// It's important to not hold the lock while calling the closure.
3438+
drop(life_tracker);
3439+
device_lost_closure.call(DeviceLostReason::Dropped, "Device is dying.".to_string());
3440+
}
34363441
#[cfg(feature = "trace")]
34373442
{
34383443
*self.trace.lock() = None;

wgpu-core/src/id.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@ pub const EPOCH_MASK: u32 = (1 << (EPOCH_BITS)) - 1;
1919

2020
/// The raw underlying representation of an identifier.
2121
#[repr(transparent)]
22-
#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))]
23-
#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))]
24-
#[cfg_attr(feature = "trace", serde(into = "SerialId"))]
25-
#[cfg_attr(feature = "replay", serde(from = "SerialId"))]
22+
#[cfg_attr(
23+
any(feature = "serde", feature = "trace"),
24+
derive(serde::Serialize),
25+
serde(into = "SerialId")
26+
)]
27+
#[cfg_attr(
28+
any(feature = "serde", feature = "replay"),
29+
derive(serde::Deserialize),
30+
serde(from = "SerialId")
31+
)]
2632
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2733
pub struct RawId(NonZeroId);
2834

@@ -129,15 +135,13 @@ enum SerialId {
129135
Id(Index, Epoch, Backend),
130136
}
131137

132-
#[cfg(feature = "trace")]
133138
impl From<RawId> for SerialId {
134139
fn from(id: RawId) -> Self {
135140
let (index, epoch, backend) = id.unzip();
136141
Self::Id(index, epoch, backend)
137142
}
138143
}
139144

140-
#[cfg(feature = "replay")]
141145
impl From<SerialId> for RawId {
142146
fn from(id: SerialId) -> Self {
143147
match id {

wgpu-core/src/instance.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,15 @@ pub enum RequestAdapterError {
471471
InvalidSurface(SurfaceId),
472472
}
473473

474+
#[derive(Clone, Debug, Error)]
475+
#[non_exhaustive]
476+
pub enum CreateSurfaceError {
477+
#[error("No backend is available")]
478+
NoSupportedBackend,
479+
#[error(transparent)]
480+
InstanceError(#[from] hal::InstanceError),
481+
}
482+
474483
impl Global {
475484
/// # Safety
476485
///
@@ -483,7 +492,7 @@ impl Global {
483492
display_handle: raw_window_handle::RawDisplayHandle,
484493
window_handle: raw_window_handle::RawWindowHandle,
485494
id_in: Option<SurfaceId>,
486-
) -> Result<SurfaceId, hal::InstanceError> {
495+
) -> Result<SurfaceId, CreateSurfaceError> {
487496
profiling::scope!("Instance::create_surface");
488497

489498
fn init<A: HalApi>(
@@ -521,8 +530,7 @@ impl Global {
521530
hal_surface = init::<hal::api::Gles>(&self.instance.gl, display_handle, window_handle);
522531
}
523532

524-
// This is only None if there's no instance at all.
525-
let hal_surface = hal_surface.unwrap()?;
533+
let hal_surface = hal_surface.ok_or(CreateSurfaceError::NoSupportedBackend)??;
526534

527535
let surface = Surface {
528536
presentation: Mutex::new(None),

0 commit comments

Comments
 (0)