diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_context.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_context.rs new file mode 100644 index 0000000000..ab900b0e54 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_context.rs @@ -0,0 +1,97 @@ +use std::collections::BTreeMap; +use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::driver::{DriverError, Result}; +use super::gem_object::GemObjectManager; +use super::gem_vma::VmaManager; + +pub type ContextHandle = u32; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ContextPriority { Low, Normal, High } + +#[derive(Clone)] +pub struct GemContext { + pub handle: ContextHandle, + pub name: Option, + pub priority: ContextPriority, + pub ppgtt_enabled: bool, + pub vma_manager: Option>, + pub active_count: u32, + pub created: bool, + pub closed: bool, +} + +pub struct ContextManager { + contexts: BTreeMap, + next_handle: AtomicU64, +} + +impl ContextManager { + pub fn new() -> Self { + Self { contexts: BTreeMap::new(), next_handle: AtomicU64::new(1) } + } + + pub fn create(&mut self, name: Option<&str>, ppgtt: bool) -> Result { + let handle = self.next_handle.fetch_add(1, Ordering::SeqCst) as ContextHandle; + let vma = if ppgtt { Some(Arc::new(VmaManager::new())) } else { None }; + + self.contexts.insert(handle, GemContext { + handle, + name: name.map(|s| s.to_string()), + priority: ContextPriority::Normal, + ppgtt_enabled: ppgtt, + vma_manager: vma, + active_count: 0, + created: true, + closed: false, + }); + Ok(handle) + } + + pub fn destroy(&mut self, handle: ContextHandle) -> Result<()> { + let ctx = self.contexts.get_mut(&handle) + .ok_or(DriverError::NotFound(format!("context {} not found", handle)))?; + if ctx.active_count > 0 { + return Err(DriverError::Buffer(format!("context {} still active ({})", handle, ctx.active_count))); + } + ctx.closed = true; + self.contexts.remove(&handle); + Ok(()) + } + + pub fn get(&self, handle: ContextHandle) -> Result<&GemContext> { + self.contexts.get(&handle) + .ok_or(DriverError::NotFound(format!("context {} not found", handle))) + } + + pub fn get_mut(&mut self, handle: ContextHandle) -> Result<&mut GemContext> { + self.contexts.get_mut(&handle) + .ok_or(DriverError::NotFound(format!("context {} not found", handle))) + } + + pub fn set_priority(&mut self, handle: ContextHandle, priority: ContextPriority) -> Result<()> { + let ctx = self.get_mut(handle)?; + ctx.priority = priority; + Ok(()) + } + + pub fn activate(&mut self, handle: ContextHandle) -> Result<()> { + let ctx = self.get_mut(handle)?; + ctx.active_count += 1; + Ok(()) + } + + pub fn deactivate(&mut self, handle: ContextHandle) -> Result<()> { + let ctx = self.get_mut(handle)?; + ctx.active_count = ctx.active_count.saturating_sub(1); + Ok(()) + } + + pub fn context_count(&self) -> usize { self.contexts.len() } +} + +pub fn create_default_context(manager: &mut ContextManager) -> Result { + manager.create(Some("default"), true) +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_domain.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_domain.rs new file mode 100644 index 0000000000..ecfc956812 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_domain.rs @@ -0,0 +1,105 @@ +use std::sync::Arc; +use std::collections::BTreeMap; + +use crate::driver::{DriverError, Result}; +use super::gem_object::GemObjectManager; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum GpuDomain { + None, Cpu, Render, Blitter, Video, Vecd, +} + +#[derive(Debug)] +pub struct DomainState { + pub read_domains: u32, + pub write_domain: u32, + pub cache_coherent: bool, + pub needs_clflush: bool, +} + +impl DomainState { + pub fn new() -> Self { + Self { read_domains: 0, write_domain: 0, cache_coherent: false, needs_clflush: false } + } +} + +pub struct DomainManager { + states: BTreeMap, +} + +impl DomainManager { + pub fn new() -> Self { Self { states: BTreeMap::new() } } + + pub fn set_domain(&mut self, handle: u32, read: u32, write: u32) -> Result<()> { + let state = self.states.entry(handle).or_insert_with(DomainState::new); + state.read_domains = read; + state.write_domain = write; + state.needs_clflush = !state.cache_coherent; + Ok(()) + } + + pub fn get_domain(&self, handle: u32) -> Option<&DomainState> { + self.states.get(&handle) + } + + pub fn is_busy(&self, handle: u32) -> bool { + self.states.get(&handle).map_or(false, |s| s.write_domain != 0) + } + + pub fn flush_for_cpu(&mut self, handle: u32) -> Result<()> { + if let Some(state) = self.states.get_mut(&handle) { + if state.needs_clflush && state.write_domain != 0 { + state.needs_clflush = false; + } + state.write_domain = 0; + } + Ok(()) + } +} + +pub struct BusyManager { + active_handles: BTreeMap, +} + +impl BusyManager { + pub fn new() -> Self { Self { active_handles: BTreeMap::new() } } + + pub fn mark_busy(&mut self, handle: u32, engine: u32) { + self.active_handles.insert(handle, engine); + } + + pub fn mark_idle(&mut self, handle: u32) { + self.active_handles.remove(&handle); + } + + pub fn is_busy(&self, handle: u32) -> bool { + self.active_handles.contains_key(&handle) + } + + pub fn busy_engine(&self, handle: u32) -> Option { + self.active_handles.get(&handle).copied() + } +} + +pub struct ThrottleManager { + pending_submissions: u32, + max_pending: u32, +} + +impl ThrottleManager { + pub fn new(max_pending: u32) -> Self { + Self { pending_submissions: 0, max_pending } + } + + pub fn throttle(&mut self) -> Result<()> { + if self.pending_submissions >= self.max_pending { + return Err(DriverError::Buffer("too many pending submissions".into())); + } + self.pending_submissions += 1; + Ok(()) + } + + pub fn retire(&mut self) { + self.pending_submissions = self.pending_submissions.saturating_sub(1); + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_mmap.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_mmap.rs new file mode 100644 index 0000000000..9163385601 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_mmap.rs @@ -0,0 +1,67 @@ +use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::collections::BTreeMap; + +use redox_driver_sys::dma::DmaBuffer; + +use super::gem_object::{CacheLevel, GemHandle, GemObjectManager}; +use crate::driver::{DriverError, Result}; + +const MMAP_OFFSET_SHIFT: u32 = 12; +const MMAP_TYPE_SHIFT: u32 = 56; +const MMAP_OFFSET_MASK: u64 = ((1u64 << MMAP_TYPE_SHIFT) - 1) & !((1u64 << MMAP_OFFSET_SHIFT) - 1); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum MmapType { WriteCombine, WriteBack, Uncached } + +#[derive(Debug)] +pub struct MmapEntry { + pub gem_handle: GemHandle, + pub mmap_type: MmapType, + pub offset: u64, + pub size: u64, + pub mapped: bool, + pub page_count: u64, +} + +pub struct MmapManager { + entries: BTreeMap, + next_offset: AtomicU64, +} + +impl MmapManager { + pub fn new() -> Self { + Self { entries: BTreeMap::new(), next_offset: AtomicU64::new(0x1000) } + } + + pub fn create_mmap(&mut self, gem_handle: GemHandle, mmap_type: MmapType, size: u64) -> Result { + let offset = self.next_offset.fetch_add(size.max(4096), Ordering::SeqCst); + let page_count = (size + 4095) / 4096; + + let mut entry = MmapEntry { + gem_handle, mmap_type, offset, size, + mapped: false, page_count, + }; + entry.mapped = true; + self.entries.insert(offset, entry); + + Ok(offset) + } + + pub fn unmap(&mut self, gem_handle: GemHandle) -> Result<()> { + self.entries.retain(|_, e| e.gem_handle != gem_handle); + Ok(()) + } + + pub fn get_offset_for_handle(&self, gem_handle: GemHandle) -> Option { + self.entries.values() + .find(|e| e.gem_handle == gem_handle) + .map(|e| e.offset) + } + + pub fn entry_for_offset(&self, offset: u64) -> Option<&MmapEntry> { + self.entries.get(&offset) + } + + pub fn active_mappings(&self) -> usize { self.entries.len() } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_stolen.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_stolen.rs new file mode 100644 index 0000000000..b28ea2e7bd --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_stolen.rs @@ -0,0 +1,87 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use redox_driver_sys::memory::MmioRegion; + +use crate::driver::{DriverError, Result}; +use super::gem_object::{GemObjectManager, MemoryRegionType}; +use super::gem_region::MemoryRegion; + +pub struct StolenMemoryManager { + region: Option, + base_address: u64, + size: u64, + reserved: BTreeMap, +} + +impl StolenMemoryManager { + pub fn new() -> Self { + Self { + region: None, base_address: 0, size: 0, + reserved: BTreeMap::new(), + } + } + + pub fn probe(&mut self, base: u64, size: u64) -> Result<()> { + if size == 0 { + return Ok(()); + } + self.base_address = base; + self.size = size; + self.region = Some(MemoryRegion::new_stolen(size, base)); + Ok(()) + } + + pub fn allocate(&mut self, size: u64, alignment: u64) -> Option { + if let Some(ref mut region) = self.region { + return region.allocate(size, alignment); + } + None + } + + pub fn free(&mut self, offset: u64, size: u64) { + if let Some(ref mut region) = self.region { + region.free(offset, size); + } + } + + pub fn reserve(&mut self, offset: u64, size: u64) { + self.reserved.insert(offset, size); + } + + pub fn available_bytes(&self) -> u64 { + self.region.as_ref().map_or(0, |r| r.free_bytes) + } + + pub fn total_bytes(&self) -> u64 { self.size } +} + +pub struct ShrinkerManager { + max_shrinkable: u64, + current_shrunk: u64, + last_shrink_attempt: Option, + shrink_count: u32, +} + +impl ShrinkerManager { + pub fn new(max: u64) -> Self { + Self { + max_shrinkable: max, current_shrunk: 0, + last_shrink_attempt: None, shrink_count: 0, + } + } + + pub fn needs_shrink(&self, required: u64) -> bool { + self.current_shrunk + required > self.max_shrinkable + } + + pub fn shrink(&mut self, object_manager: &mut GemObjectManager, target: u64) -> Result { + let mut freed: u64 = 0; + self.shrink_count += 1; + self.last_shrink_attempt = Some(std::time::Instant::now()); + self.current_shrunk = self.current_shrunk.saturating_sub(freed); + Ok(freed) + } + + pub fn shrink_count(&self) -> u32 { self.shrink_count } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_tiling.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_tiling.rs new file mode 100644 index 0000000000..9be69f843b --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_tiling.rs @@ -0,0 +1,98 @@ +use crate::driver::Result; +use super::gem_object::MemoryRegionType; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TilingMode { None, X, Y, Yf, Ys } + +#[derive(Clone, Copy, Debug)] +pub struct TilingConfig { + pub mode: TilingMode, + pub stride: u32, + pub fence_reg: Option, + pub fence_reg_start: Option, + pub fence_reg_size: Option, +} + +impl TilingConfig { + pub fn new() -> Self { + Self { mode: TilingMode::None, stride: 0, fence_reg: None, fence_reg_start: None, fence_reg_size: None } + } +} + +pub struct FenceRegisterManager { + fence_regs: [Option; 32], + active_fences: u32, +} + +impl FenceRegisterManager { + pub fn new() -> Self { + Self { fence_regs: [None; 32], active_fences: 0 } + } + + pub fn allocate_fence(&mut self, start: u64, size: u64) -> Option { + for i in 0..32 { + if self.fence_regs[i].is_none() { + self.fence_regs[i] = Some(start); + self.active_fences += 1; + return Some(i as u32); + } + } + None + } + + pub fn release_fence(&mut self, reg: u32) -> Result<()> { + if (reg as usize) < 32 && self.fence_regs[reg as usize].is_some() { + self.fence_regs[reg as usize] = None; + self.active_fences -= 1; + } + Ok(()) + } + + pub fn fence_count(&self) -> u32 { self.active_fences } +} + +pub struct TilingManager { + configs: std::collections::BTreeMap, + fences: FenceRegisterManager, +} + +impl TilingManager { + pub fn new() -> Self { + Self { configs: std::collections::BTreeMap::new(), fences: FenceRegisterManager::new() } + } + + pub fn set_tiling(&mut self, handle: u32, mode: TilingMode, stride: u32) -> Result<()> { + let config = self.configs.entry(handle).or_insert_with(TilingConfig::new); + config.mode = mode; + config.stride = stride; + Ok(()) + } + + pub fn get_tiling(&self, handle: u32) -> Option { + self.configs.get(&handle).copied() + } + + pub fn needs_fence_register(&self, handle: u32, size: u64) -> bool { + if let Some(cfg) = self.configs.get(&handle) { + if cfg.mode == TilingMode::X && size > 512 * 1024 * 1024 { return true; } + } + false + } + + pub fn get_fence(&self, handle: u32) -> Option { + self.configs.get(&handle).and_then(|c| c.fence_reg) + } + + pub fn allocate_fence_for_handle(&mut self, handle: u32, gtt_offset: u64, size: u64) -> Result> { + if !self.needs_fence_register(handle, size) { return Ok(None); } + if let Some(reg) = self.fences.allocate_fence(gtt_offset, size) { + if let Some(cfg) = self.configs.get_mut(&handle) { + cfg.fence_reg = Some(reg); + cfg.fence_reg_start = Some(gtt_offset); + cfg.fence_reg_size = Some(size); + } + return Ok(Some(reg)); + } + Ok(None) + } +} 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 ecea47168e..b79e9633bb 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 @@ -1,11 +1,21 @@ +pub mod gem_context; +pub mod gem_domain; pub mod gem_execbuffer; +pub mod gem_mmap; pub mod gem_object; pub mod gem_pages; pub mod gem_region; +pub mod gem_stolen; +pub mod gem_tiling; pub mod gem_vma; +pub use gem_context::{ContextManager, ContextPriority, GemContext, create_default_context}; +pub use gem_domain::{BusyManager, DomainManager, DomainState, GpuDomain, ThrottleManager}; pub use gem_execbuffer::{ExecObject, ExecbufferManager, ExecbufferSubmission, RelocationEntry}; +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_stolen::{ShrinkerManager, StolenMemoryManager}; +pub use gem_tiling::{FenceRegisterManager, TilingConfig, TilingManager, TilingMode}; pub use gem_vma::{AddressSpaceType, GemVma, VmaManager};