-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add syncobj support and poll-based example
* syncobj::Handle and syncobj::SyncFile types added * These types may be used in device-specific Card implementations to add multiple-event asynchronicity of command submissions.
- Loading branch information
1 parent
a7d1dc1
commit ca05f55
Showing
9 changed files
with
583 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ license = "MIT" | |
authors = ["Tyler Slabinski <[email protected]>", "Victoria Brekenfeld <[email protected]>"] | ||
exclude = [".gitignore", ".github"] | ||
rust-version = "1.63" | ||
resolver = "2" # Required to separate dev-dependencies.nix features | ||
|
||
[dependencies] | ||
bitflags = "1" | ||
|
@@ -19,6 +20,11 @@ version = "0.26.0" | |
default-features = false | ||
features = ["mman"] | ||
|
||
[dev-dependencies.nix] | ||
version = "0.26.0" | ||
default-features = false | ||
features = ["mman", "poll"] | ||
|
||
[dev-dependencies] | ||
image = { version = "^0.23.14", default-features = false, features = ["png"] } | ||
rustyline = "^8.0.0" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
//! | ||
//! Bindings for DRM sync objects | ||
//! | ||
|
||
use drm_sys::*; | ||
use ioctl; | ||
|
||
use result::SystemError as Error; | ||
use std::os::unix::io::RawFd; | ||
|
||
/// Creates a syncobj. | ||
pub fn create(fd: RawFd, signaled: bool) -> Result<drm_syncobj_create, Error> { | ||
let mut args = drm_syncobj_create { | ||
handle: 0, | ||
flags: if signaled { | ||
DRM_SYNCOBJ_CREATE_SIGNALED | ||
} else { | ||
0 | ||
}, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::create(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Destroys a syncobj. | ||
pub fn destroy(fd: RawFd, handle: u32) -> Result<drm_syncobj_destroy, Error> { | ||
let mut args = drm_syncobj_destroy { handle, pad: 0 }; | ||
|
||
unsafe { | ||
ioctl::syncobj::destroy(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Exports a syncobj as an inter-process file descriptor or as a poll()-able sync file. | ||
pub fn handle_to_fd( | ||
fd: RawFd, | ||
handle: u32, | ||
export_sync_file: bool, | ||
) -> Result<drm_syncobj_handle, Error> { | ||
let mut args = drm_syncobj_handle { | ||
handle, | ||
flags: if export_sync_file { | ||
DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE | ||
} else { | ||
0 | ||
}, | ||
fd: 0, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::handle_to_fd(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Imports a file descriptor exported by [`handle_to_fd`] back into a process-local handle. | ||
pub fn fd_to_handle( | ||
fd: RawFd, | ||
syncobj_fd: RawFd, | ||
import_sync_file: bool, | ||
) -> Result<drm_syncobj_handle, Error> { | ||
let mut args = drm_syncobj_handle { | ||
handle: 0, | ||
flags: if import_sync_file { | ||
DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE | ||
} else { | ||
0 | ||
}, | ||
fd: syncobj_fd, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::fd_to_handle(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Waits for one or more syncobjs to become signalled. | ||
pub fn wait( | ||
fd: RawFd, | ||
handles: &[u32], | ||
timeout_nsec: i64, | ||
wait_all: bool, | ||
wait_for_submit: bool, | ||
) -> Result<drm_syncobj_wait, Error> { | ||
let mut args = drm_syncobj_wait { | ||
handles: handles.as_ptr() as _, | ||
timeout_nsec, | ||
count_handles: handles.len() as _, | ||
flags: if wait_all { | ||
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | ||
} else { | ||
0 | ||
} | if wait_for_submit { | ||
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | ||
} else { | ||
0 | ||
}, | ||
first_signaled: 0, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::wait(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Resets (un-signals) one or more syncobjs. | ||
pub fn reset(fd: RawFd, handles: &[u32]) -> Result<drm_syncobj_array, Error> { | ||
let mut args = drm_syncobj_array { | ||
handles: handles.as_ptr() as _, | ||
count_handles: handles.len() as _, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::reset(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Signals one or more syncobjs. | ||
pub fn signal(fd: RawFd, handles: &[u32]) -> Result<drm_syncobj_array, Error> { | ||
let mut args = drm_syncobj_array { | ||
handles: handles.as_ptr() as _, | ||
count_handles: handles.len() as _, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::signal(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Waits for one or more specific timeline syncobj points. | ||
pub fn timeline_wait( | ||
fd: RawFd, | ||
handles: &[u32], | ||
points: &[u64], | ||
timeout_nsec: i64, | ||
wait_all: bool, | ||
wait_for_submit: bool, | ||
wait_available: bool, | ||
) -> Result<drm_syncobj_timeline_wait, Error> { | ||
debug_assert_eq!(handles.len(), points.len()); | ||
|
||
let mut args = drm_syncobj_timeline_wait { | ||
handles: handles.as_ptr() as _, | ||
points: points.as_ptr() as _, | ||
timeout_nsec, | ||
count_handles: handles.len() as _, | ||
flags: if wait_all { | ||
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | ||
} else { | ||
0 | ||
} | if wait_for_submit { | ||
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | ||
} else { | ||
0 | ||
} | if wait_available { | ||
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE | ||
} else { | ||
0 | ||
}, | ||
first_signaled: 0, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::timeline_wait(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Queries for state of one or more timeline syncobjs. | ||
pub fn query( | ||
fd: RawFd, | ||
handles: &[u32], | ||
points: &mut [u64], | ||
last_submitted: bool, | ||
) -> Result<drm_syncobj_timeline_array, Error> { | ||
debug_assert_eq!(handles.len(), points.len()); | ||
|
||
let mut args = drm_syncobj_timeline_array { | ||
handles: handles.as_ptr() as _, | ||
points: points.as_ptr() as _, | ||
count_handles: handles.len() as _, | ||
flags: if last_submitted { | ||
DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | ||
} else { | ||
0 | ||
}, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::query(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Transfers one timeline syncobj point to another. | ||
pub fn transfer( | ||
fd: RawFd, | ||
src_handle: u32, | ||
dst_handle: u32, | ||
src_point: u64, | ||
dst_point: u64, | ||
) -> Result<drm_syncobj_transfer, Error> { | ||
let mut args = drm_syncobj_transfer { | ||
src_handle, | ||
dst_handle, | ||
src_point, | ||
dst_point, | ||
flags: 0, | ||
pad: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::transfer(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} | ||
|
||
/// Signals one or more specific timeline syncobj points. | ||
pub fn timeline_signal( | ||
fd: RawFd, | ||
handles: &[u32], | ||
points: &[u64], | ||
) -> Result<drm_syncobj_timeline_array, Error> { | ||
debug_assert_eq!(handles.len(), points.len()); | ||
|
||
let mut args = drm_syncobj_timeline_array { | ||
handles: handles.as_ptr() as _, | ||
points: points.as_ptr() as _, | ||
count_handles: handles.len() as _, | ||
flags: 0, | ||
}; | ||
|
||
unsafe { | ||
ioctl::syncobj::timeline_signal(fd, &mut args)?; | ||
} | ||
|
||
Ok(args) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
extern crate drm; | ||
extern crate image; | ||
extern crate nix; | ||
|
||
/// Check the `util` module to see how the `Card` structure is implemented. | ||
pub mod utils; | ||
|
||
use nix::poll::PollFlags; | ||
use std::os::unix::io::AsRawFd; | ||
use utils::*; | ||
|
||
use drm::control::syncobj::SyncFile; | ||
use drm::SystemError; | ||
|
||
impl Card { | ||
fn simulate_command_submission(&self) -> Result<SyncFile, SystemError> { | ||
// Create a temporary syncobj to receive the command fence. | ||
let syncobj = self.create_syncobj(false)?; | ||
|
||
let sync_file = { | ||
// Fake a command submission by signalling the syncobj immediately. The kernel | ||
// attaches a null fence object which is always signalled. Other than this, there | ||
// isn't a good way to create and signal a fence object from user-mode, so an actual | ||
// device is required to test this properly. | ||
// | ||
// For a real device, the syncobj handle should be passed to a command submission | ||
// which is expected to set a fence to be signalled upon completion. | ||
self.syncobj_signal(&[syncobj])?; | ||
|
||
// Export fence set by previous ioctl to file descriptor. | ||
self.syncobj_to_fd(syncobj, true) | ||
}; | ||
|
||
// The sync file descriptor constitutes ownership of the fence, so the syncobj can be | ||
// safely destroyed. | ||
self.destroy_syncobj(syncobj)?; | ||
|
||
sync_file | ||
} | ||
} | ||
|
||
fn main() { | ||
let card = Card::open_global(); | ||
let sync_file = card.simulate_command_submission().unwrap(); | ||
|
||
// Poll for readability. The DRM fence object will directly wake the thread when signalled. | ||
// | ||
// Alternatively, Tokio's AsyncFd may be used like so: | ||
// | ||
// use tokio::io::{Interest, unix::AsyncFd}; | ||
// let afd = AsyncFd::with_interest(sync_file, Interest::READABLE).unwrap(); | ||
// let future = async move { afd.readable().await.unwrap().retain_ready() }; | ||
// future.await; | ||
let mut poll_fds = [nix::poll::PollFd::new( | ||
sync_file.as_raw_fd(), | ||
PollFlags::POLLIN, | ||
)]; | ||
nix::poll::poll(&mut poll_fds, -1).unwrap(); | ||
} |
Oops, something went wrong.