-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Host and Device Memory Pool with initial CUDA support + port of existing code. #201
Changes from all commits
4d815d1
9554df9
c0bfb83
bd6045e
2885ba1
4b46676
4fd781e
7ab0e4b
293b61a
6d1ad33
6728066
6810079
d56710a
fc0f4af
01f76e9
ad6fc8b
7790574
f74c5b0
722578b
8e81a51
993d777
91ca118
0bce6d7
ba67a64
0e14cc0
c0bcc7a
a206ed0
1ab5201
bf912c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,22 @@ | ||
use cu29::prelude::{CuBufferHandle, CuHostMemoryPool}; | ||
use cu29::prelude::CuPool; | ||
use cu29::prelude::{CuHandle, CuHostMemoryPool}; | ||
use std::convert::TryInto; | ||
use std::rc::Rc; | ||
use std::time::Duration; | ||
use std::{io, mem, sync::Arc}; | ||
use v4l::buffer::{Metadata, Type}; | ||
use v4l::device::Handle; | ||
use v4l::io::traits::{CaptureStream, Stream}; | ||
use v4l::memory::Memory; | ||
use v4l::v4l_sys::*; | ||
use v4l::v4l_sys::{v4l2_buffer, v4l2_buffer__bindgen_ty_1, v4l2_format, v4l2_requestbuffers}; | ||
use v4l::{v4l2, Device}; | ||
|
||
// A specialized V4L stream that uses Copper Buffers for memory management. | ||
pub struct CuV4LStream { | ||
v4l_handle: Arc<Handle>, | ||
v4l_buf_type: Type, | ||
memory_pool: Rc<CuHostMemoryPool>, | ||
memory_pool: CuHostMemoryPool<Vec<u8>>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should streams own pools or borrow them from an application? Maybe creating a singular big pool and splitting it out per device would be helpful. Granted, that's what the OS is doing when you ask to create a pool in the first place but if we have all these sizes done at compile time, it's a nice way to measure memory footprint |
||
// Arena matching the vl42 metadata and the Copper Buffers | ||
arena: Vec<(Metadata, Option<CuBufferHandle>)>, | ||
arena: Vec<(Metadata, Option<CuHandle<Vec<u8>>>)>, | ||
arena_last_freed_up_index: usize, | ||
timeout: Option<i32>, | ||
active: bool, | ||
|
@@ -34,13 +34,13 @@ impl CuV4LStream { | |
buf_size: usize, | ||
buf_count: u32, | ||
) -> io::Result<Self> { | ||
let memory_pool = CuHostMemoryPool::new(buf_size, buf_count + 1, page_size::get()); // +1 to be able to queue one last buffer before zapping the first | ||
let memory_pool = CuHostMemoryPool::new(buf_count as usize + 1, || vec![0; buf_size]); // +1 to be able to queue one last buffer before zapping the first | ||
let mut arena = Vec::new(); | ||
arena.resize(buf_count as usize, (Metadata::default(), None)); | ||
|
||
let mut result = CuV4LStream { | ||
v4l_handle: dev.handle(), | ||
memory_pool: Rc::new(memory_pool), | ||
memory_pool, | ||
arena, | ||
arena_last_freed_up_index: 0, | ||
v4l_buf_type: buf_type, | ||
|
@@ -151,7 +151,7 @@ impl Drop for CuV4LStream { | |
} | ||
|
||
impl Stream for CuV4LStream { | ||
type Item = CuBufferHandle; | ||
type Item = CuHandle<Vec<u8>>; | ||
|
||
fn start(&mut self) -> io::Result<()> { | ||
// Enqueue all buffers once on stream start | ||
|
@@ -191,28 +191,27 @@ impl Stream for CuV4LStream { | |
|
||
impl CaptureStream<'_> for CuV4LStream { | ||
fn queue(&mut self, index: usize) -> io::Result<()> { | ||
let buffer_handle = CuHostMemoryPool::allocate(&self.memory_pool).ok_or(io::Error::new( | ||
io::ErrorKind::Other, | ||
"Failed to allocate buffer", | ||
))?; | ||
let buffer_handle = self.memory_pool.acquire().unwrap(); | ||
self.arena[index] = (Metadata::default(), Some(buffer_handle.clone())); | ||
let mut v4l2_buf = buffer_handle.with_inner_mut(|inner| { | ||
let destination: &mut [u8] = inner; | ||
|
||
let buf: &[u8] = buffer_handle.as_slice(); | ||
let mut v4l2_buf = v4l2_buffer { | ||
index: index as u32, | ||
m: v4l2_buffer__bindgen_ty_1 { | ||
userptr: buf.as_ptr() as std::os::raw::c_ulong, | ||
}, | ||
length: buf.len() as u32, | ||
..self.buffer_desc() | ||
}; | ||
v4l2_buffer { | ||
index: index as u32, | ||
m: v4l2_buffer__bindgen_ty_1 { | ||
userptr: destination.as_ptr() as std::os::raw::c_ulong, | ||
}, | ||
length: destination.len() as u32, | ||
..self.buffer_desc() | ||
} | ||
}); | ||
unsafe { | ||
v4l2::ioctl( | ||
self.v4l_handle.fd(), | ||
v4l2::vidioc::VIDIOC_QBUF, | ||
&mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, | ||
)?; | ||
} | ||
self.arena[index] = (Metadata::default(), Some(buffer_handle)); | ||
Ok(()) | ||
} | ||
|
||
|
@@ -238,12 +237,6 @@ impl CaptureStream<'_> for CuV4LStream { | |
)?; | ||
} | ||
let index = v4l2_buf.index as usize; | ||
// println!("dequeue: dequeueing buffer {}", index); | ||
// println!(" length {}", v4l2_buf.length); | ||
// println!(" bytesused {}", v4l2_buf.bytesused); | ||
// println!(" timestamp {:?}", v4l2_buf.timestamp); | ||
// println!(" sequence {}", v4l2_buf.sequence); | ||
// println!(" field {}", v4l2_buf.field); | ||
|
||
self.arena[index].0 = Metadata { | ||
bytesused: v4l2_buf.bytesused, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be interesting to have a memory pool as a task itself where requests for memory come in and handles come out. The lack of synchronicity would be a bit awkward but the messaging system would handle concurrent buffer requests coming in at the same time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, it would be very awkward, but I agree with a kind of "factory" that we need also for monitoring purposes. I am implementing that now.
Thanks!