Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent Metal from crashing when a still-open encoder is deallocated, resolve issue #2077. #4023

Merged
merged 22 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
75b5056
This prevents Metal from crashing when an encoder is deallocated.
bradwerth Aug 9, 2023
7ce2f9a
Add note to CHANGELOG.md.
bradwerth Aug 9, 2023
baf3fa3
Add note to CHANGELOG.md.
bradwerth Aug 9, 2023
7e21d4c
Relocate additions in CHANGELOG.md.
bradwerth Aug 9, 2023
d896931
Merge branch 'endEncoding' of https://github.com/bradwerth/wgpu into …
bradwerth Aug 9, 2023
db5cb6d
Fix changelog and add code comment describing the motivation for thes…
bradwerth Aug 10, 2023
386eacc
Merge branch 'trunk' into endEncoding
bradwerth Aug 11, 2023
0425f63
Instead of implementing Drop for CommandState, implement it for
bradwerth Aug 11, 2023
00411bc
Merge branch 'trunk' into endEncoding
bradwerth Aug 15, 2023
a4eaa94
Implement Drop for DX12 CommandEncoders to also call discard_encoding.
bradwerth Aug 16, 2023
c4d5691
Update Changelog with notes about DX12 changes.
bradwerth Aug 16, 2023
3c44ed7
Merge branch 'trunk' into endEncoding
bradwerth Aug 16, 2023
9f55d32
Fix DX12 compilation problems, attempt 1.
bradwerth Aug 16, 2023
2cbb242
Merge branch 'trunk' into endEncoding
bradwerth Aug 16, 2023
59446b8
Update comment with the narrower finding of the endEncoding requirement.
bradwerth Aug 16, 2023
305fd55
Mark the drop_encoder_after_error test as failing on DX12.
bradwerth Aug 16, 2023
64a029f
Cleanup of some should-be-left-untouched DX12 implementation stuff.
bradwerth Aug 17, 2023
dd53269
Merge branch 'trunk' into endEncoding
bradwerth Aug 17, 2023
7215c93
Merge branch 'trunk' into endEncoding
bradwerth Aug 17, 2023
bdb4515
Merge branch 'trunk' into endEncoding
bradwerth Aug 18, 2023
e3afadc
Merge branch 'trunk' into endEncoding
bradwerth Aug 20, 2023
3e2ec42
CHANGELOG.md: Avoid duplicating "Bug Fixes" section
jimblandy Aug 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ Bottom level categories:

## Unreleased

### Bug Fixes

#### DX12

- Ensure that CommandAllocator closes the command list before it is reset.

By @bradwerth in [#4203](https://github.com/gfx-rs/wgpu/pull/4023)

#### Metal

- Ensure that MTLCommandEncoder calls endEncoding before it is deallocated.

By @bradwerth in [#4203](https://github.com/gfx-rs/wgpu/pull/4023)

### Major changes

#### Pass timestamp queries
Expand Down Expand Up @@ -111,7 +125,7 @@ This release was fairly minor as breaking changes go.

#### `wgpu` types now `!Send` `!Sync` on wasm

Up until this point, wgpu has made the assumption that threads do not exist on wasm. With the rise of libraries like [`wasm_thread`](https://crates.io/crates/wasm_thread) making it easier and easier to do wasm multithreading this assumption is no longer sound. As all wgpu objects contain references into the JS heap, they cannot leave the thread they started on.
Up until this point, wgpu has made the assumption that threads do not exist on wasm. With the rise of libraries like [`wasm_thread`](https://crates.io/crates/wasm_thread) making it easier and easier to do wasm multithreading this assumption is no longer sound. As all wgpu objects contain references into the JS heap, they cannot leave the thread they started on.
bradwerth marked this conversation as resolved.
Show resolved Hide resolved

As we understand that this change might be very inconvenient for users who don't care about wasm threading, there is a crate feature which re-enables the old behavior: `fragile-send-sync-non-atomic-wasm`. So long as you don't compile your code with `-Ctarget-feature=+atomics`, `Send` and `Sync` will be implemented again on wgpu types on wasm. As the name implies, especially for libraries, this is very fragile, as you don't know if a user will want to compile with atomics (and therefore threads) or not.

Expand Down
51 changes: 50 additions & 1 deletion tests/tests/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use wasm_bindgen_test::*;
use wgpu_test::{initialize_test, TestParameters};
use wgpu::RenderPassDescriptor;
use wgpu_test::{fail, initialize_test, TestParameters};

#[test]
#[wasm_bindgen_test]
Expand All @@ -11,3 +12,51 @@ fn drop_encoder() {
drop(encoder);
})
}

#[test]
fn drop_encoder_after_error() {
initialize_test(TestParameters::default(), |ctx| {
let mut encoder = ctx
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());

let target_tex = ctx.device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width: 100,
height: 100,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Unorm,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let target_view = target_tex.create_view(&wgpu::TextureViewDescriptor::default());

let mut renderpass = encoder.begin_render_pass(&RenderPassDescriptor {
label: Some("renderpass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
ops: wgpu::Operations::default(),
resolve_target: None,
view: &target_view,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});

// Set a bad viewport on renderpass, triggering an error.
fail(&ctx.device, || {
renderpass.set_viewport(0.0, 0.0, -1.0, -1.0, 0.0, 1.0);
drop(renderpass);
});

// This is the actual interesting error condition. We've created
// a CommandEncoder which errored out when processing a command.
// The encoder is still open!
drop(encoder);
})
}
11 changes: 11 additions & 0 deletions wgpu-hal/src/dx12/command.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::auxil::{self, dxgi::result::HResult as _};
use crate::CommandEncoder as _;

use super::conv;
use std::{mem, ops::Range, ptr};
Expand Down Expand Up @@ -1192,3 +1193,13 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
};
}
}

impl Drop for super::CommandEncoder {
fn drop(&mut self) {
// DX12 throws an exception when an encoder is dropped without being closed.
// To prevent this, we explicitiy call discard_encoding.
unsafe {
self.discard_encoding();
}
bradwerth marked this conversation as resolved.
Show resolved Hide resolved
}
}
15 changes: 15 additions & 0 deletions wgpu-hal/src/metal/command.rs
bradwerth marked this conversation as resolved.
Show resolved Hide resolved
bradwerth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{conv, AsNative};
use crate::CommandEncoder as _;
use std::{borrow::Cow, mem, ops::Range};

// has to match `Temp::binding_sizes`
Expand Down Expand Up @@ -1054,3 +1055,17 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
encoder.dispatch_thread_groups_indirect(&buffer.raw, offset, self.state.raw_wg_size);
}
}

impl Drop for super::CommandEncoder {
fn drop(&mut self) {
// Metal raises an assert when a MTLCommandEncoder is deallocated without a call
// to endEncoding. This isn't documented at
// https://developer.apple.com/documentation/metal/mtlcommandencoder?language=objc
// but it manifests as a crash with the message 'Command encoder released without
// endEncoding'. To prevent this, we explicitiy call discard_encoding, which
// calls end_encoding on any still-held metal::CommandEncoders.
unsafe {
self.discard_encoding();
}
}
}