diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_request.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_request.rs new file mode 100644 index 0000000000..6ff59e59ed --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_request.rs @@ -0,0 +1,166 @@ +use std::collections::{BTreeMap, VecDeque}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::Instant; + +use crate::driver::{DriverError, Result}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum EngineClass { Render, Blitter, Video, VideoEnhance, Compute } + +#[derive(Clone, Debug)] +pub struct GemRequest { + pub fence: u64, + pub ctx_id: u32, + pub engine: EngineClass, + pub gem_handles: Vec, + pub submitted: Option, + pub completed: Option, + pub priority: i32, +} + +pub struct RequestManager { + requests: BTreeMap, + next_fence: AtomicU64, + completed_queue: VecDeque, + max_inflight: u32, +} + +impl RequestManager { + pub fn new(max_inflight: u32) -> Self { + Self { + requests: BTreeMap::new(), + next_fence: AtomicU64::new(1), + completed_queue: VecDeque::new(), + max_inflight, + } + } + + pub fn create(&mut self, ctx_id: u32, engine: EngineClass, handles: &[u32], priority: i32) -> Result { + if self.requests.len() >= self.max_inflight as usize { + return Err(DriverError::Buffer("max inflight requests".into())); + } + let fence = self.next_fence.fetch_add(1, Ordering::SeqCst); + self.requests.insert(fence, GemRequest { + fence, ctx_id, engine, + gem_handles: handles.to_vec(), + submitted: Some(Instant::now()), + completed: None, priority, + }); + Ok(fence) + } + + pub fn complete(&mut self, fence: u64) -> Result<()> { + if let Some(req) = self.requests.get_mut(&fence) { + req.completed = Some(Instant::now()); + self.completed_queue.push_back(fence); + } + Ok(()) + } + + pub fn retire_completed(&mut self) -> Vec { + let mut retired = Vec::new(); + while let Some(fence) = self.completed_queue.pop_front() { + if self.requests.remove(&fence).is_some() { + retired.push(fence); + } + } + retired + } + + pub fn get(&self, fence: u64) -> Option<&GemRequest> { + self.requests.get(&fence) + } + + pub fn inflight_count(&self) -> usize { self.requests.len() } + pub fn pending_count(&self) -> usize { self.requests.len() - self.completed_queue.len() } + + pub fn pending_for_context(&self, ctx_id: u32) -> Vec { + self.requests.iter() + .filter(|(_, r)| r.ctx_id == ctx_id && r.completed.is_none()) + .map(|(f, _)| *f) + .collect() + } +} + +pub struct Scheduler { + runqueues: BTreeMap>, +} + +#[derive(Clone, Debug)] +pub struct QueuedRequest { + pub fence: u64, + pub ctx_id: u32, + pub engine: EngineClass, + pub priority: i32, + pub queued_at: Instant, +} + +impl Scheduler { + pub fn new() -> Self { + Self { runqueues: BTreeMap::new() } + } + + pub fn enqueue(&mut self, fence: u64, ctx_id: u32, engine: EngineClass, priority: i32) { + self.runqueues.entry(priority).or_default().push_back(QueuedRequest { + fence, ctx_id, engine, priority, queued_at: Instant::now(), + }); + } + + pub fn dequeue(&mut self) -> Option { + let mut priorities: Vec = self.runqueues.keys().copied().collect(); + priorities.sort_by(|a, b| b.cmp(a)); + for priority in priorities { + if let Some(queue) = self.runqueues.get_mut(&priority) { + if let Some(req) = queue.pop_front() { + if queue.is_empty() { + self.runqueues.remove(&priority); + } + return Some(req); + } + } + } + None + } + + pub fn pending_count(&self) -> usize { + self.runqueues.values().map(|q| q.len()).sum() + } +} + +pub struct GemStatistics { + pub total_created: u64, + pub total_closed: u64, + pub total_submitted: u64, + pub total_completed: u64, + pub total_retired: u64, + pub peak_inflight: u64, + pub peak_objects: u64, + pub total_bytes_allocated: u64, + pub total_bytes_freed: u64, +} + +impl GemStatistics { + pub fn new() -> Self { + Self { + total_created: 0, total_closed: 0, + total_submitted: 0, total_completed: 0, total_retired: 0, + peak_inflight: 0, peak_objects: 0, + total_bytes_allocated: 0, total_bytes_freed: 0, + } + } + + pub fn record_create(&mut self) { self.total_created += 1; } + pub fn record_close(&mut self) { self.total_closed += 1; } + pub fn record_submit(&mut self, inflight: u64) { + self.total_submitted += 1; + self.peak_inflight = self.peak_inflight.max(inflight); + } + pub fn record_complete(&mut self) { self.total_completed += 1; } + pub fn record_retire(&mut self) { self.total_retired += 1; } + pub fn record_alloc(&mut self, bytes: u64) { + self.total_bytes_allocated += bytes; + } + pub fn record_free(&mut self, bytes: u64) { + self.total_bytes_freed += bytes; + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/mod.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/mod.rs index 1cbf408fc4..2963e55899 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/mod.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/mod.rs @@ -11,6 +11,7 @@ pub mod gem_mmap; pub mod gem_object; pub mod gem_pages; pub mod gem_region; +pub mod gem_request; pub mod gem_stolen; pub mod gem_tiling; pub mod gem_ttm; @@ -29,6 +30,7 @@ pub use gem_mmap::{MmapEntry, MmapManager, MmapType}; pub use gem_object::{CacheLevel, GemHandle, GemObject, GemObjectManager, MemoryRegionType}; pub use gem_pages::{PageManager, TtmMoveManager}; pub use gem_region::MemoryRegion; +pub use gem_request::{EngineClass, GemRequest, GemStatistics, RequestManager, Scheduler}; pub use gem_stolen::{ShrinkerManager, StolenMemoryManager}; pub use gem_tiling::{FenceRegisterManager, TilingConfig, TilingManager, TilingMode}; pub use gem_ttm::{Migration, PowerManager, TtmManager};