diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de1a4423..daae803c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -120,6 +120,20 @@ pub enum PollError { By @cwfitzgerald in [#6942](https://github.com/gfx-rs/wgpu/pull/6942). By @cwfitzgerald in [#7030](https://github.com/gfx-rs/wgpu/pull/7030). +#### `wgpu::Device::start_capture` renamed, documented, and made unsafe + +```diff +- device.start_capture(); ++ unsafe { device.start_graphics_debugger_capture() } +// Your code here +- device.stop_capture(); ++ unsafe { device.stop_graphics_debugger_capture() } +``` + +There is now documentation to describe how this maps to the various debuggers' apis. + +By @cwfitzgerald in [#7470](https://github.com/gfx-rs/wgpu/pull/7470) + #### Naga ##### Ensure loops generated by SPIR-V and HLSL Naga backends are bounded diff --git a/deno_webgpu/device.rs b/deno_webgpu/device.rs index 77f5966c5..c69477bb4 100644 --- a/deno_webgpu/device.rs +++ b/deno_webgpu/device.rs @@ -610,14 +610,17 @@ impl GPUDevice { #[fast] fn start_capture(&self) { - self.instance.device_start_capture(self.id); + unsafe { + self.instance + .device_start_graphics_debugger_capture(self.id) + }; } #[fast] fn stop_capture(&self) { self.instance .device_poll(self.id, wgpu_types::PollType::wait()) .unwrap(); - self.instance.device_stop_capture(self.id); + unsafe { self.instance.device_stop_graphics_debugger_capture(self.id) }; } } diff --git a/examples/standalone/custom_backend/src/custom.rs b/examples/standalone/custom_backend/src/custom.rs index 6a30b8f7d..1c04ab0f4 100644 --- a/examples/standalone/custom_backend/src/custom.rs +++ b/examples/standalone/custom_backend/src/custom.rs @@ -236,11 +236,11 @@ impl DeviceInterface for CustomDevice { unimplemented!() } - fn start_capture(&self) { + unsafe fn start_graphics_debugger_capture(&self) { unimplemented!() } - fn stop_capture(&self) { + unsafe fn stop_graphics_debugger_capture(&self) { unimplemented!() } diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 1e76cb2fd..719a5c096 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -99,13 +99,13 @@ fn main() { log::info!("Executing actions"); #[cfg(not(feature = "winit"))] { - global.device_start_capture(device); + unsafe { global.device_start_graphics_debugger_capture(device) }; while let Some(action) = actions.pop() { global.process(device, queue, action, &dir, &mut command_buffer_id_manager); } - global.device_stop_capture(device); + unsafe { global.device_stop_graphics_debugger_capture(device) }; global.device_poll(device, wgt::PollType::wait()).unwrap(); } #[cfg(feature = "winit")] diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index d7c83d0b3..5d19bd362 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -2025,26 +2025,36 @@ impl Global { Ok(all_queue_empty) } - pub fn device_start_capture(&self, device_id: DeviceId) { - api_log!("Device::start_capture"); + /// # Safety + /// + /// - See [wgpu::Device::start_graphics_debugger_capture][api] for details the safety. + /// + /// [api]: ../../wgpu/struct.Device.html#method.start_graphics_debugger_capture + pub unsafe fn device_start_graphics_debugger_capture(&self, device_id: DeviceId) { + api_log!("Device::start_graphics_debugger_capture"); let device = self.hub.devices.get(device_id); if !device.is_valid() { return; } - unsafe { device.raw().start_capture() }; + unsafe { device.raw().start_graphics_debugger_capture() }; } - pub fn device_stop_capture(&self, device_id: DeviceId) { - api_log!("Device::stop_capture"); + /// # Safety + /// + /// - See [wgpu::Device::stop_graphics_debugger_capture][api] for details the safety. + /// + /// [api]: ../../wgpu/struct.Device.html#method.stop_graphics_debugger_capture + pub unsafe fn device_stop_graphics_debugger_capture(&self, device_id: DeviceId) { + api_log!("Device::stop_graphics_debugger_capture"); let device = self.hub.devices.get(device_id); if !device.is_valid() { return; } - unsafe { device.raw().stop_capture() }; + unsafe { device.raw().stop_graphics_debugger_capture() }; } pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option> { diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index cdc641866..290ece8ef 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -2112,7 +2112,7 @@ impl crate::Device for super::Device { } } - unsafe fn start_capture(&self) -> bool { + unsafe fn start_graphics_debugger_capture(&self) -> bool { #[cfg(feature = "renderdoc")] { unsafe { @@ -2124,7 +2124,7 @@ impl crate::Device for super::Device { false } - unsafe fn stop_capture(&self) { + unsafe fn stop_graphics_debugger_capture(&self) { #[cfg(feature = "renderdoc")] unsafe { self.render_doc diff --git a/wgpu-hal/src/dynamic/device.rs b/wgpu-hal/src/dynamic/device.rs index c0de61f88..76cd47c5c 100644 --- a/wgpu-hal/src/dynamic/device.rs +++ b/wgpu-hal/src/dynamic/device.rs @@ -146,8 +146,8 @@ pub trait DynDevice: DynResource { timeout_ms: u32, ) -> Result; - unsafe fn start_capture(&self) -> bool; - unsafe fn stop_capture(&self); + unsafe fn start_graphics_debugger_capture(&self) -> bool; + unsafe fn stop_graphics_debugger_capture(&self); unsafe fn pipeline_cache_get_data(&self, cache: &dyn DynPipelineCache) -> Option>; @@ -504,12 +504,12 @@ impl DynDevice for D { unsafe { D::wait(self, fence, value, timeout_ms) } } - unsafe fn start_capture(&self) -> bool { - unsafe { D::start_capture(self) } + unsafe fn start_graphics_debugger_capture(&self) -> bool { + unsafe { D::start_graphics_debugger_capture(self) } } - unsafe fn stop_capture(&self) { - unsafe { D::stop_capture(self) } + unsafe fn stop_graphics_debugger_capture(&self) { + unsafe { D::stop_graphics_debugger_capture(self) } } unsafe fn pipeline_cache_get_data(&self, cache: &dyn DynPipelineCache) -> Option> { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index e3f3f61a3..45c7b1b92 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1572,7 +1572,7 @@ impl crate::Device for super::Device { fence.wait(gl, wait_value, timeout_ns) } - unsafe fn start_capture(&self) -> bool { + unsafe fn start_graphics_debugger_capture(&self) -> bool { #[cfg(all(native, feature = "renderdoc"))] return unsafe { self.render_doc @@ -1581,7 +1581,7 @@ impl crate::Device for super::Device { #[allow(unreachable_code)] false } - unsafe fn stop_capture(&self) { + unsafe fn stop_graphics_debugger_capture(&self) { #[cfg(all(native, feature = "renderdoc"))] unsafe { self.render_doc diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index aa997a2d9..2a37c2507 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -971,8 +971,23 @@ pub trait Device: WasmNotSendSync { timeout_ms: u32, ) -> Result; - unsafe fn start_capture(&self) -> bool; - unsafe fn stop_capture(&self); + /// Start a graphics debugger capture. + /// + /// # Safety + /// + /// See [`wgpu::Device::start_graphics_debugger_capture`][api] for more details. + /// + /// [api]: ../wgpu/struct.Device.html#method.start_graphics_debugger_capture + unsafe fn start_graphics_debugger_capture(&self) -> bool; + + /// Stop a graphics debugger capture. + /// + /// # Safety + /// + /// See [`wgpu::Device::stop_graphics_debugger_capture`][api] for more details. + /// + /// [api]: ../wgpu/struct.Device.html#method.stop_graphics_debugger_capture + unsafe fn stop_graphics_debugger_capture(&self); #[allow(unused_variables)] unsafe fn pipeline_cache_get_data( diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 6fb172d00..17456fa03 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -1491,7 +1491,7 @@ impl crate::Device for super::Device { } } - unsafe fn start_capture(&self) -> bool { + unsafe fn start_graphics_debugger_capture(&self) -> bool { if !self.shared.private_caps.supports_capture_manager { return false; } @@ -1503,7 +1503,8 @@ impl crate::Device for super::Device { default_capture_scope.begin_scope(); true } - unsafe fn stop_capture(&self) { + + unsafe fn stop_graphics_debugger_capture(&self) { let shared_capture_manager = metal::CaptureManager::shared(); if let Some(default_capture_scope) = shared_capture_manager.default_capture_scope() { default_capture_scope.end_scope(); diff --git a/wgpu-hal/src/noop/mod.rs b/wgpu-hal/src/noop/mod.rs index f5f985392..929ff329f 100644 --- a/wgpu-hal/src/noop/mod.rs +++ b/wgpu-hal/src/noop/mod.rs @@ -426,10 +426,10 @@ impl crate::Device for Context { Ok(true) } - unsafe fn start_capture(&self) -> bool { + unsafe fn start_graphics_debugger_capture(&self) -> bool { false } - unsafe fn stop_capture(&self) {} + unsafe fn stop_graphics_debugger_capture(&self) {} unsafe fn create_acceleration_structure( &self, desc: &crate::AccelerationStructureDescriptor, diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index c00792de9..b2734b763 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -2531,7 +2531,7 @@ impl crate::Device for super::Device { self.shared.wait_for_fence(fence, wait_value, timeout_ns) } - unsafe fn start_capture(&self) -> bool { + unsafe fn start_graphics_debugger_capture(&self) -> bool { #[cfg(feature = "renderdoc")] { // Renderdoc requires us to give us the pointer that vkInstance _points to_. @@ -2546,7 +2546,7 @@ impl crate::Device for super::Device { #[cfg(not(feature = "renderdoc"))] false } - unsafe fn stop_capture(&self) { + unsafe fn stop_graphics_debugger_capture(&self) { #[cfg(feature = "renderdoc")] { // Renderdoc requires us to give us the pointer that vkInstance _points to_. diff --git a/wgpu/src/api/device.rs b/wgpu/src/api/device.rs index 5971b061d..05ca2020e 100644 --- a/wgpu/src/api/device.rs +++ b/wgpu/src/api/device.rs @@ -377,14 +377,65 @@ impl Device { self.inner.pop_error_scope() } - /// Starts frame capture. - pub fn start_capture(&self) { - self.inner.start_capture() + /// Starts a capture in the attached graphics debugger. + /// + /// This behaves differently depending on which graphics debugger is attached: + /// + /// - Renderdoc: Calls [`StartFrameCapture(device, NULL)`][rd]. + /// - Xcode: Creates a capture with [`MTLCaptureManager`][xcode]. + /// - None: No action is taken. + /// + /// # Safety + /// + /// - There should not be any other captures currently active. + /// - All other safety rules are defined by the graphics debugger, see the + /// documentation for the specific debugger. + /// - In general, graphics debuggers can easily cause crashes, so this isn't + /// ever guaranteed to be sound. + /// + /// # Tips + /// + /// - Debuggers need to capture both the recording of the commands and the + /// submission of the commands to the GPU. Try to wrap all of your + /// gpu work in a capture. + /// - If you encounter issues, try waiting for the GPU to finish all work + /// before stopping the capture. + /// + /// [rd]: https://renderdoc.org/docs/in_application_api.html#_CPPv417StartFrameCapture23RENDERDOC_DevicePointer22RENDERDOC_WindowHandle + /// [xcode]: https://developer.apple.com/documentation/metal/mtlcapturemanager + #[doc(alias = "start_renderdoc_capture")] + #[doc(alias = "start_xcode_capture")] + pub unsafe fn start_graphics_debugger_capture(&self) { + unsafe { self.inner.start_graphics_debugger_capture() } } - /// Stops frame capture. - pub fn stop_capture(&self) { - self.inner.stop_capture() + /// Stops the current capture in the attached graphics debugger. + /// + /// This behaves differently depending on which graphics debugger is attached: + /// + /// - Renderdoc: Calls [`EndFrameCapture(device, NULL)`][rd]. + /// - Xcode: Stops the capture with [`MTLCaptureManager`][xcode]. + /// - None: No action is taken. + /// + /// # Safety + /// + /// - There should be a capture currently active. + /// - All other safety rules are defined by the graphics debugger, see the + /// documentation for the specific debugger. + /// - In general, graphics debuggers can easily cause crashes, so this isn't + /// ever guaranteed to be sound. + /// + /// # Tips + /// + /// - If you encounter issues, try to submit all work to the GPU, and waiting + /// for that work to finish before stopping the capture. + /// + /// [rd]: https://renderdoc.org/docs/in_application_api.html#_CPPv415EndFrameCapture23RENDERDOC_DevicePointer22RENDERDOC_WindowHandle + /// [xcode]: https://developer.apple.com/documentation/metal/mtlcapturemanager + #[doc(alias = "stop_renderdoc_capture")] + #[doc(alias = "stop_xcode_capture")] + pub unsafe fn stop_graphics_debugger_capture(&self) { + unsafe { self.inner.stop_graphics_debugger_capture() } } /// Query internal counters from the native backend for debugging purposes. diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index d7a76384f..eb97554dd 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -2394,11 +2394,11 @@ impl dispatch::DeviceInterface for WebDevice { )) } - fn start_capture(&self) { + unsafe fn start_graphics_debugger_capture(&self) { // No capturing api in webgpu } - fn stop_capture(&self) { + unsafe fn stop_graphics_debugger_capture(&self) { // No capturing api in webgpu } diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 2b9030ce3..98c1ba8d3 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -1646,12 +1646,20 @@ impl dispatch::DeviceInterface for CoreDevice { Box::pin(ready(scope.error)) } - fn start_capture(&self) { - self.context.0.device_start_capture(self.id); + unsafe fn start_graphics_debugger_capture(&self) { + unsafe { + self.context + .0 + .device_start_graphics_debugger_capture(self.id) + }; } - fn stop_capture(&self) { - self.context.0.device_stop_capture(self.id); + unsafe fn stop_graphics_debugger_capture(&self) { + unsafe { + self.context + .0 + .device_stop_graphics_debugger_capture(self.id) + }; } fn poll(&self, poll_type: crate::PollType) -> Result { diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index 07924d914..0e4bbc70a 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -161,8 +161,8 @@ pub trait DeviceInterface: CommonTraits { fn push_error_scope(&self, filter: crate::ErrorFilter); fn pop_error_scope(&self) -> Pin>; - fn start_capture(&self); - fn stop_capture(&self); + unsafe fn start_graphics_debugger_capture(&self); + unsafe fn stop_graphics_debugger_capture(&self); fn poll(&self, poll_type: crate::PollType) -> Result;