diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_execbuffer.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_execbuffer.rs new file mode 100644 index 0000000000..0265edd320 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_execbuffer.rs @@ -0,0 +1,61 @@ +use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; +use crate::driver::{DriverError, Result}; +use super::gem_object::GemObjectManager; +use super::gem_vma::{AddressSpaceType, VmaManager}; + +#[derive(Clone, Debug)] +pub struct ExecObject { + pub handle: u32, pub offset: u32, pub length: u32, + pub flags: u32, pub gtt_offset: u64, pub needs_binding: bool, +} +#[derive(Clone, Debug)] +pub struct RelocationEntry { + pub target_handle: u32, pub delta: u32, pub offset: u32, +} +#[derive(Clone, Debug)] +pub struct ExecbufferSubmission { + pub objects: Vec, + pub relocations: Vec, + pub batch_start_offset: u32, pub batch_len: u32, + pub flags: u32, pub ctx_id: u32, +} + +pub struct ExecbufferManager { + object_manager: Arc, + vma_manager: std::sync::Mutex, + next_fence: AtomicU64, +} + +impl ExecbufferManager { + pub fn new(om: Arc, vm: VmaManager) -> Self { + Self { object_manager: om, vma_manager: std::sync::Mutex::new(vm), next_fence: AtomicU64::new(1) } + } + + pub fn submit(&mut self, sub: &ExecbufferSubmission) -> Result { + for obj in &sub.objects { + let gem = self.object_manager.get(obj.handle)?; + if obj.offset as u64 + obj.length as u64 > gem.size { + return Err(DriverError::Buffer(format!("exec object {} overflow", obj.handle))); + } + } + for reloc in &sub.relocations { + let _target = self.object_manager.get(reloc.target_handle)?; + let found = sub.objects.iter().any(|o| + reloc.offset >= o.offset && reloc.offset + 8 <= o.offset + o.length); + if !found && !sub.objects.is_empty() { + return Err(DriverError::Buffer("relocation outside batch objects".into())); + } + } + for obj in &sub.objects { + if !obj.needs_binding { continue; } + let gem = self.object_manager.get(obj.handle)?; + if let Some(gtt) = gem.gtt_offset { + let va = gtt + obj.offset as u64; + let id = self.vma_manager.lock().unwrap().create_vma(obj.handle, AddressSpaceType::Ggtt, va, obj.length as u64)?; + self.vma_manager.lock().unwrap().bind(id)?; + } + } + Ok(self.next_fence.fetch_add(1, Ordering::SeqCst)) + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_pages.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_pages.rs new file mode 100644 index 0000000000..0901313534 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_pages.rs @@ -0,0 +1,83 @@ +use std::collections::BTreeMap; +use redox_driver_sys::dma::DmaBuffer; +use crate::driver::{DriverError, Result}; + +pub struct PageManager { + pages: BTreeMap, + page_size: u64, + total_allocated: u64, +} + +pub struct Page { + pub phys_addr: u64, + pub refcount: u32, + pub dirty: bool, +} + +impl PageManager { + pub fn new(page_size: u64) -> Self { + Self { pages: BTreeMap::new(), page_size, total_allocated: 0 } + } + + pub fn allocate(&mut self, phys_addr: u64) -> Result<()> { + self.pages.entry(phys_addr).or_insert_with(|| { + self.total_allocated += self.page_size; + Page { phys_addr, refcount: 1, dirty: false } + }); + Ok(()) + } + + pub fn free(&mut self, phys_addr: u64) -> Result<()> { + if let Some(page) = self.pages.get_mut(&phys_addr) { + page.refcount = page.refcount.saturating_sub(1); + if page.refcount == 0 { + self.total_allocated -= self.page_size; + self.pages.remove(&phys_addr); + } + } + Ok(()) + } + + pub fn mark_dirty(&mut self, phys_addr: u64) -> Result<()> { + if let Some(page) = self.pages.get_mut(&phys_addr) { page.dirty = true; } + Ok(()) + } + + pub fn page_count(&self, size: u64) -> u64 { (size + self.page_size - 1) / self.page_size } + pub fn total_allocated(&self) -> u64 { self.total_allocated } +} + +pub struct TtmMoveManager { + src_free: u64, + dst_free: u64, + src_total: u64, + dst_total: u64, +} + +impl TtmMoveManager { + pub fn new() -> Self { + Self { src_free: 0, dst_free: 0, src_total: 0, dst_total: 0 } + } + + pub fn init(&mut self, src_total: u64, dst_total: u64) { + self.src_total = src_total; self.src_free = src_total; + self.dst_total = dst_total; self.dst_free = dst_total; + } + + pub fn migrate(&mut self, size: u64, alignment: u64) -> Result<(u64, u64)> { + let aligned = (size + alignment - 1) / alignment * alignment; + if aligned > self.src_free || aligned > self.dst_free { + return Err(DriverError::Buffer("TTM move: insufficient space".into())); + } + let src_off = self.src_total - self.src_free; + let dst_off = self.dst_total - self.dst_free; + self.src_free -= aligned; + self.dst_free -= aligned; + Ok((src_off, dst_off)) + } + + pub fn free(&mut self, size: u64, src: bool) { + if src { self.src_free = (self.src_free + size).min(self.src_total); } + else { self.dst_free = (self.dst_free + size).min(self.dst_total); } + } +} 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 26028b6f9a..ecea47168e 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,7 +1,11 @@ +pub mod gem_execbuffer; pub mod gem_object; +pub mod gem_pages; pub mod gem_region; pub mod gem_vma; +pub use gem_execbuffer::{ExecObject, ExecbufferManager, ExecbufferSubmission, RelocationEntry}; pub use gem_object::{CacheLevel, GemHandle, GemObject, GemObjectManager, MemoryRegionType}; +pub use gem_pages::{PageManager, TtmMoveManager}; pub use gem_region::MemoryRegion; pub use gem_vma::{AddressSpaceType, GemVma, VmaManager};