Rename and unsafe start_capture -> start_graphics_debugger_capture (#7470)

* Improve `start_capture` docs

* Docs
This commit is contained in:
Connor Fitzgerald 2025-04-03 13:07:22 -04:00 committed by GitHub
parent eea54c221c
commit c860a2cf8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 146 additions and 44 deletions

View File

@ -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

View File

@ -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) };
}
}

View File

@ -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!()
}

View File

@ -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")]

View File

@ -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<Vec<u8>> {

View File

@ -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

View File

@ -146,8 +146,8 @@ pub trait DynDevice: DynResource {
timeout_ms: u32,
) -> Result<bool, DeviceError>;
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<Vec<u8>>;
@ -504,12 +504,12 @@ impl<D: Device + DynResource> 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<Vec<u8>> {

View File

@ -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

View File

@ -971,8 +971,23 @@ pub trait Device: WasmNotSendSync {
timeout_ms: u32,
) -> Result<bool, DeviceError>;
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(

View File

@ -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();

View File

@ -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,

View File

@ -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_.

View File

@ -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.

View File

@ -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
}

View File

@ -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<crate::PollStatus, crate::PollError> {

View File

@ -161,8 +161,8 @@ pub trait DeviceInterface: CommonTraits {
fn push_error_scope(&self, filter: crate::ErrorFilter);
fn pop_error_scope(&self) -> Pin<Box<dyn PopErrorScopeFuture>>;
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<crate::PollStatus, crate::PollError>;