Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ repository.
- [Browser sources on the GPU under Mesa](/quest/m0/cef-headless.md) - shared-texture pages paint on Intel and AMD under Wayland, and a page that cannot paint fails loudly
- [A browser helper exits with the studio](/quest/m0/browser-helper-exit.md) - no orphaned CEF helper after a crash, kill, or timed-out test
- [Nightly and the browser suite pass](/quest/m0/nightly-green.md) - render-sw, cookies, and the X11 clipboard test fixed at their causes
- [GPU tests exit cleanly on NVIDIA](/quest/m0/gpu-tests-exit.md) - compositor tests no longer crash on exit on NVIDIA
- [The Apple signing identity is available](/quest/m0/signing.md) - the Apple credentials packaging and the macOS camera need; Windows ships unsigned
- [Packaging](/quest/m0/packaging.md) - a signed macOS app, a Windows installer, and a Flatpak for Linux
- [The persistable portal restore token is pinned](/quest/m0/pin-portal-token.md) - moq-video's restore token, for Wayland sources
Expand Down
17 changes: 0 additions & 17 deletions quest/m0/gpu-tests-exit.md

This file was deleted.

32 changes: 24 additions & 8 deletions rs/moq-scene/src/matte.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ fn segment(model: &Model, rgba: &[u8]) -> Result<Vec<u8>, String> {
run().map_err(|err| format!("the segmentation model: {err}"))
}

/// Cuts a person out of one source's pictures. Dropping it stops its thread
/// once the picture in hand is done.
/// Cuts a person out of one source's pictures. Dropping it waits for the
/// picture in hand, then stops its thread.
pub(crate) struct Matte {
device: wgpu::Device,
queue: wgpu::Queue,
Expand All @@ -83,8 +83,13 @@ pub(crate) struct Matte {
mask_bind: wgpu::BindGroup,
/// The newest picture started, and its cut-out, at its size.
held: Option<Held>,
jobs: mpsc::Sender<wgpu::SubmissionIndex>,
/// Dropped first on drop, which ends the thread.
jobs: Option<mpsc::Sender<wgpu::SubmissionIndex>>,
results: mpsc::Receiver<Result<Vec<u8>, String>>,
/// Joined on drop, since the thread frees GPU objects on its way out: one
/// left running past `main` does so while the driver tears down, which
/// crashes NVIDIA's.
thread: Option<std::thread::JoinHandle<()>>,
/// Whether the thread has a picture, which also has `readback` mapped.
busy: bool,
/// Whether the picture the thread has was overtaken, so its cut-out is
Expand Down Expand Up @@ -211,13 +216,13 @@ impl Matte {

let (jobs, inbox) = mpsc::channel();
let (outbox, results) = mpsc::channel();
let thread = Thread {
let worker = Thread {
device: device.clone(),
readback: readback.clone(),
};
std::thread::Builder::new()
let thread = std::thread::Builder::new()
.name("moq-scene matte".into())
.spawn(move || thread.run(inbox, outbox))
.spawn(move || worker.run(inbox, outbox))
.map_err(|err| Error::Unsupported(format!("cannot start background removal: {err}")))?;

Ok(Self {
Expand All @@ -233,8 +238,9 @@ impl Matte {
mask,
mask_bind,
held: None,
jobs,
jobs: Some(jobs),
results,
thread: Some(thread),
busy: false,
stale: false,
#[cfg(test)]
Expand Down Expand Up @@ -276,7 +282,8 @@ impl Matte {
let submission = self.queue.submit([encoder.finish()]);
self.held = Some(held);
// A thread that is gone reports so through `finish`.
let _ = self.jobs.send(submission);
let jobs = self.jobs.as_ref().expect("the job sender lives until drop");
let _ = jobs.send(submission);
self.busy = true;
}

Expand Down Expand Up @@ -413,6 +420,15 @@ impl Matte {
}
}

impl Drop for Matte {
fn drop(&mut self) {
drop(self.jobs.take());
if let Some(thread) = self.thread.take() {
let _ = thread.join();
}
}
}

/// What a matte's thread holds: the device to wait on, and the buffer the
/// shrunk picture lands in.
struct Thread {
Expand Down
26 changes: 23 additions & 3 deletions rs/moq-scene/src/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,13 +904,18 @@ fn fonts() -> FontContext {

/// The overlays a compositor draws. Their documents live on a thread of their
/// own, since a Blitz document cannot leave the thread that made it, and a
/// panic there fails the overlays rather than the compositor.
/// panic there fails the overlays rather than the compositor. Dropping it
/// stops the thread and waits for it.
pub(crate) struct Overlays {
device: wgpu::Device,
requests: mpsc::Sender<Request>,
/// What each paint failed on, by overlay.
painted: mpsc::Receiver<Vec<(u64, String)>>,
next: u64,
/// Joined on drop, since the thread frees GPU objects on its way out: one
/// left running past `main` does so while the driver tears down, which
/// crashes NVIDIA's.
thread: Option<std::thread::JoinHandle<()>>,
}

enum Request {
Expand All @@ -928,6 +933,8 @@ enum Request {
Restart(u64, Instant),
/// Paint these overlays as of this time on the program clock.
Paint(Instant, Vec<u64>),
/// End the thread, though an [`Overlay`] may still hold a sender.
Stop,
/// Stop the thread the way a panic in Blitz would.
#[cfg(test)]
Panic,
Expand All @@ -939,7 +946,7 @@ impl Overlays {
let (requests, received) = mpsc::channel();
let (reply, painted) = mpsc::channel();
let (device, queue) = (device.clone(), queue.clone());
std::thread::Builder::new()
let thread = std::thread::Builder::new()
.name("overlays".into())
.spawn({
let device = device.clone();
Expand All @@ -951,6 +958,7 @@ impl Overlays {
requests,
painted,
next: 0,
thread: Some(thread),
})
}

Expand Down Expand Up @@ -1008,6 +1016,17 @@ impl Overlays {
}
}

impl Drop for Overlays {
fn drop(&mut self) {
// A thread that already stopped has nothing left to free, and one
// that panicked already failed every overlay.
let _ = self.requests.send(Request::Stop);
if let Some(thread) = self.thread.take() {
let _ = thread.join();
}
}
}

#[cfg(test)]
impl Overlays {
/// Stop the thread as a panic in Blitz would.
Expand Down Expand Up @@ -1056,7 +1075,7 @@ impl Drop for Overlay {
}
}

/// The overlay thread: serve requests until every sender is gone.
/// The overlay thread: serve requests until told to stop.
fn run(
device: &wgpu::Device,
queue: &wgpu::Queue,
Expand Down Expand Up @@ -1099,6 +1118,7 @@ fn run(
document.painted = false;
}
}
Request::Stop => return,
#[cfg(test)]
Request::Panic => panic!("a test stopped the overlay thread"),
Request::Paint(now, ids) => {
Expand Down