Skip to content

Commit 4bef272

Browse files
authored
Fix loading of renderdoc library (#140)
* Fix loading of RenderDoc library It turns out this crate has been loading the RenderDoc API incorrectly: > To do this you'll use your platforms dynamic library functions to see > if the library is open already - e.g. `GetModuleHandle` on Windows, or > or `dlopen` with the `RTLD_NOW | RTLD_NOLOAD` flags if available on > *nix systems. On most platforms you can just search for the module > name - `renderdoc.dll` on Windows, or `librenderdoc.so` on Linux, or > `libVkLayer_GLES_RenderDoc.so` on Android should be sufficient here, > so you don’t need to know the path to where RenderDoc is running from. > This will vary by platform however so consult your platform’s OS > documentation. Then you can use `GetProcAddress` or `dlsym` to fetch > the `RENDERDOC_GetAPI` function using the typedef above. This was reported long ago as an issue, and I'm addressing this now with this commit. It does change the runtime behavior of the library, though: the application no longer attempts to load RenderDoc into memory if not injected from the outside, so `RenderDoc::new()` will now return `Err` when previously it would have succeeded. * Restore integration and doctest support in CI This commit adds an unstable `ci` feature which reverts back the previous non-compliant opening method because it enables tests to run in CI without needing to painstakingly extract the test binary names from `cargo build --tests --message-format json` and spawn each one in `renderdoccmd capture $NAME`. Besides, this strategy is impossible anyway because doctests compiled on-the-fly by `rustdoc` and do not have external binaries with which to launch with RenderDoc. We also cannot make the `RTLD_NOLOAD` conditional, i.e. `#[cfg(any(test, doctest))]` and `#[cfg(not(any(test, doctest)))]`, due to: rust-lang/rust#67295 As such, this internal crate feature will have to do.
1 parent 5384f04 commit 4bef272

File tree

3 files changed

+43
-31
lines changed

3 files changed

+43
-31
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ all-features = true
1919
[badges]
2020
circle-ci = { repository = "ebkalderon/renderdoc-rs" }
2121

22+
[features]
23+
default = []
24+
25+
# Private feature only intended for doctests in CI
26+
ci = []
27+
2228
[dependencies]
2329
bitflags = "1.0"
2430
float-cmp = "0.9"

examples/triangle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
3838
.await
3939
.expect("Failed to create device");
4040

41-
let mut rd: RenderDoc<V110> = RenderDoc::new().unwrap();
41+
let mut rd: RenderDoc<V110> = RenderDoc::new().expect("RenderDoc is not running");
4242
rd.set_focus_toggle_keys(&[InputButton::F]);
4343
rd.set_capture_keys(&[InputButton::C]);
4444

src/version.rs

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,14 @@
11
//! Entry points for the RenderDoc API.
22
3-
use std::os::raw::c_void;
4-
use std::path::Path;
3+
use std::ffi::c_void;
4+
use std::ptr;
55

66
use libloading::{Library, Symbol};
77
use once_cell::sync::OnceCell;
88
use renderdoc_sys::RENDERDOC_API_1_4_1;
99

1010
use crate::error::Error;
1111

12-
static RD_LIB: OnceCell<Library> = OnceCell::new();
13-
14-
#[cfg(windows)]
15-
fn get_path() -> &'static Path {
16-
Path::new("renderdoc.dll")
17-
}
18-
19-
#[cfg(all(unix, not(target_os = "android")))]
20-
fn get_path() -> &'static Path {
21-
Path::new("librenderdoc.so")
22-
}
23-
24-
#[cfg(target_os = "android")]
25-
fn get_path() -> &'static Path {
26-
Path::new("libVkLayer_GLES_RenderDoc.so")
27-
}
28-
2912
/// Entry point for the RenderDoc API.
3013
pub type Entry = RENDERDOC_API_1_4_1;
3114

@@ -55,13 +38,6 @@ pub enum VersionCode {
5538
V141 = 10401,
5639
}
5740

58-
/// Initializes a new instance of the RenderDoc API.
59-
///
60-
/// # Safety
61-
///
62-
/// This function is not thread-safe and should not be called on multiple threads at once.
63-
type GetApiFn = unsafe extern "C" fn(ver: VersionCode, out: *mut *mut c_void) -> i32;
64-
6541
/// Entry point into the RenderDoc API.
6642
pub trait Version {
6743
/// Minimum compatible version number.
@@ -73,18 +49,48 @@ pub trait Version {
7349
///
7450
/// This function is not thread-safe and should not be called on multiple threads at once.
7551
fn load() -> Result<*mut Entry, Error> {
76-
use std::ptr;
52+
static LIBRARY: OnceCell<Library> = OnceCell::new();
53+
54+
type GetApiFn = unsafe extern "C" fn(ver: u32, out: *mut *mut c_void) -> i32;
55+
56+
#[cfg(windows)]
57+
let lib_path = "renderdoc.dll";
58+
#[cfg(all(unix, not(target_os = "android")))]
59+
let lib_path = "librenderdoc.so";
60+
#[cfg(target_os = "android")]
61+
let lib_path = "libVkLayer_GLES_RenderDoc.so";
7762

7863
unsafe {
79-
let lib = RD_LIB
80-
.get_or_try_init(|| Library::new(get_path()))
64+
#[cfg(not(feature = "ci"))]
65+
#[cfg(unix)]
66+
let lib = LIBRARY
67+
.get_or_try_init(|| {
68+
// TODO: Use constant from `libloading`, once added upstream.
69+
const RTLD_NOLOAD: i32 = 0x4;
70+
71+
let flags = libloading::os::unix::RTLD_NOW | RTLD_NOLOAD;
72+
libloading::os::unix::Library::open(Some(lib_path), flags).map(Into::into)
73+
})
74+
.map_err(Error::library)?;
75+
76+
#[cfg(not(feature = "ci"))]
77+
#[cfg(windows)]
78+
let lib = LIBRARY
79+
.get_or_try_init(|| {
80+
libloading::os::windows::Library::open_already_loaded(lib_path).map(Into::into)
81+
})
82+
.map_err(Error::library)?;
83+
84+
#[cfg(feature = "ci")]
85+
let lib = LIBRARY
86+
.get_or_try_init(|| Library::new(lib_path))
8187
.map_err(Error::library)?;
8288

8389
let get_api: Symbol<GetApiFn> =
8490
lib.get(b"RENDERDOC_GetAPI\0").map_err(Error::symbol)?;
8591

8692
let mut obj = ptr::null_mut();
87-
match get_api(Self::VERSION, &mut obj) {
93+
match get_api(Self::VERSION as u32, &mut obj) {
8894
1 => Ok(obj as *mut Entry),
8995
_ => Err(Error::no_compatible_api()),
9096
}

0 commit comments

Comments
 (0)