wgpu_hal/auxil/
renderdoc.rs
1#![cfg_attr(not(any(feature = "gles", feature = "vulkan")), allow(dead_code))]
3
4use alloc::format;
5use alloc::string::String;
6use core::{ffi, ptr};
7
8#[repr(C)]
10#[derive(Debug)]
11pub struct RenderDocApi {
12 api: renderdoc_sys::RENDERDOC_API_1_4_1,
13 lib: libloading::Library,
14}
15
16unsafe impl Send for RenderDocApi {}
17unsafe impl Sync for RenderDocApi {}
18
19#[derive(Debug)]
21pub enum RenderDoc {
22 Available {
24 api: RenderDocApi,
26 },
27 NotAvailable {
29 reason: String,
31 },
32}
33
34#[cfg(unix)]
36const RTLD_NOLOAD: i32 = 0x4;
37
38impl RenderDoc {
39 pub unsafe fn new() -> Self {
40 type GetApiFn = unsafe extern "C" fn(version: u32, out: *mut *mut ffi::c_void) -> i32;
41
42 #[cfg(windows)]
43 let renderdoc_filename = "renderdoc.dll";
44 #[cfg(all(unix, not(target_os = "android")))]
45 let renderdoc_filename = "librenderdoc.so";
46 #[cfg(target_os = "android")]
47 let renderdoc_filename = "libVkLayer_GLES_RenderDoc.so";
48
49 #[cfg(unix)]
50 let renderdoc_result: Result<libloading::Library, libloading::Error> = unsafe {
51 libloading::os::unix::Library::open(
52 Some(renderdoc_filename),
53 libloading::os::unix::RTLD_NOW | RTLD_NOLOAD,
54 )
55 }
56 .map(|lib| lib.into());
57
58 #[cfg(windows)]
59 let renderdoc_result: Result<libloading::Library, libloading::Error> =
60 libloading::os::windows::Library::open_already_loaded(renderdoc_filename)
61 .map(|lib| lib.into());
62
63 let renderdoc_lib = match renderdoc_result {
64 Ok(lib) => lib,
65 Err(e) => {
66 return RenderDoc::NotAvailable {
67 reason: format!(
68 "Unable to load renderdoc library '{renderdoc_filename}': {e:?}"
69 ),
70 }
71 }
72 };
73
74 let get_api: libloading::Symbol<GetApiFn> =
75 match unsafe { renderdoc_lib.get(c"RENDERDOC_GetAPI".to_bytes()) } {
76 Ok(api) => api,
77 Err(e) => {
78 return RenderDoc::NotAvailable {
79 reason: format!(
80 "Unable to get RENDERDOC_GetAPI from renderdoc library '{renderdoc_filename}': {e:?}"
81 ),
82 }
83 }
84 };
85 let mut obj = ptr::null_mut();
86 match unsafe { get_api(10401, &mut obj) } {
87 1 => RenderDoc::Available {
88 api: RenderDocApi {
89 api: unsafe { *obj.cast::<renderdoc_sys::RENDERDOC_API_1_4_1>() },
90 lib: renderdoc_lib,
91 },
92 },
93 return_value => RenderDoc::NotAvailable {
94 reason: format!(
95 "Unable to get API from renderdoc library '{renderdoc_filename}': {return_value}"
96 ),
97 },
98 }
99 }
100}
101
102impl Default for RenderDoc {
103 fn default() -> Self {
104 if !cfg!(debug_assertions) {
105 return RenderDoc::NotAvailable {
106 reason: "RenderDoc support is only enabled with 'debug_assertions'".into(),
107 };
108 }
109 unsafe { Self::new() }
110 }
111}
112pub type Handle = *mut ffi::c_void;
114
115impl RenderDoc {
116 pub unsafe fn start_frame_capture(&self, device_handle: Handle, window_handle: Handle) -> bool {
118 match *self {
119 Self::Available { api: ref entry } => {
120 unsafe { entry.api.StartFrameCapture.unwrap()(device_handle, window_handle) };
121 true
122 }
123 Self::NotAvailable { ref reason } => {
124 log::warn!("Could not start RenderDoc frame capture: {reason}");
125 false
126 }
127 }
128 }
129
130 pub unsafe fn end_frame_capture(&self, device_handle: Handle, window_handle: Handle) {
132 match *self {
133 Self::Available { api: ref entry } => {
134 unsafe { entry.api.EndFrameCapture.unwrap()(device_handle, window_handle) };
135 }
136 Self::NotAvailable { ref reason } => {
137 log::warn!("Could not end RenderDoc frame capture: {reason}")
138 }
139 };
140 }
141}