intel: GEM render state, fence registers, FBC tracking

gem_state.rs (170 lines):
  RenderState: gen-specific golden context initialization
    init_gen9: STATE_BASE_ADDRESS + CC_STATE_POINTERS programming
    init_gen8: simplified context image
    GGTT-backed with proper page mapping

  FenceRegisterState: 32-slot fence register pool
    allocate/release with tiling + pitch tracking
    find_by_handle reverse lookup
    used_count query

  FrameBufferCompressionState:
    Register/unregister scanout buffers
    mark_compressed/uncompressed with CFB offset tracking
    Per-buffer compressed byte accounting

Ported from Linux 7.1:
  i915_gem_render_state.c → RenderState
  i915_gem_fence.c → FenceRegisterState
  i915_gem_gtt.c (partial) → FBC tracking

GEM subdirectory: 23 files, 2,030 lines, 0 errors
This commit is contained in:
2026-06-02 10:11:01 +03:00
parent f904f59b68
commit eff3e6a850
2 changed files with 188 additions and 0 deletions
@@ -0,0 +1,186 @@
use log::info;
use super::super::gtt::IntelGtt;
use crate::driver::Result;
const GEN9_RENDER_STATE_SIZE: usize = 4096;
const GEN8_RENDER_STATE_SIZE: usize = 2048;
pub struct RenderState {
buffer: Vec<u32>,
gpu_addr: u64,
initialized: bool,
}
impl RenderState {
pub fn new() -> Self {
Self { buffer: Vec::new(), gpu_addr: 0, initialized: false }
}
pub fn init_gen9(&mut self, gtt: &mut IntelGtt) -> Result<()> {
self.buffer.clear();
self.buffer.extend_from_slice(&[
0x1100_0001, // MI_LOAD_REGISTER_IMM
0x2244, // register offset
0x0000_0001, // value
]);
self.buffer.extend_from_slice(&[
0x1100_0001, // MI_LOAD_REGISTER_IMM
0x20D8, // STATE_BASE_ADDRESS
0x0000_0001, // General State Base Address
0xFFFF_F001, // General State Base Address Upper
0xFFFF_0001, // Dynamic State Base Address
0xFFFF_F001, // Dynamic State Base Address Upper
0xFFFF_0001, // Indirect Object Base Address
0xFFFF_F001, // Indirect Object Base Address Upper
0xFFFF_0001, // Instruction Base Address
0xFFFF_F001, // Instruction Base Address Upper
]);
self.buffer.extend_from_slice(&[
0x6101_0008, // 3DSTATE_CC_STATE_POINTERS
0x0000_0001,
0x0000_0001,
]);
self.buffer.extend_from_slice(&[
0x0500_0000, // MI_BATCH_BUFFER_END
]);
let aligned_size = ((self.buffer.len() * 4 + 4095) / 4096) * 4096;
self.gpu_addr = gtt.alloc_range(aligned_size as u64)?;
gtt.map_range(self.gpu_addr, 0, aligned_size as u64, (1 << 0) | (1 << 1))?;
self.initialized = true;
info!("redox-drm-intel: Gen9 render state initialized at {:#x} ({} dwords)", self.gpu_addr, self.buffer.len());
Ok(())
}
pub fn init_gen8(&mut self, gtt: &mut IntelGtt) -> Result<()> {
self.buffer.extend_from_slice(&[
0x1100_0001, 0x2244, 0x0000_0001,
]);
self.buffer.extend_from_slice(&[
0x0500_0000,
]);
let aligned_size = ((self.buffer.len() * 4 + 4095) / 4096) * 4096;
self.gpu_addr = gtt.alloc_range(aligned_size as u64)?;
gtt.map_range(self.gpu_addr, 0, aligned_size as u64, (1 << 0) | (1 << 1))?;
self.initialized = true;
info!("redox-drm-intel: Gen8 render state initialized at {:#x}", self.gpu_addr);
Ok(())
}
pub fn is_initialized(&self) -> bool { self.initialized }
pub fn gpu_addr(&self) -> u64 { self.gpu_addr }
pub fn dword_count(&self) -> usize { self.buffer.len() }
}
pub struct FenceRegisterState {
registers: [Option<FenceReg>; 32],
}
#[derive(Clone, Copy, Debug)]
pub struct FenceReg {
pub handle: u32,
pub start: u64,
pub size: u64,
pub tiled: bool,
pub pitch: u32,
}
impl FenceRegisterState {
pub fn new() -> Self { Self { registers: [None; 32] } }
pub fn allocate(&mut self, handle: u32, start: u64, size: u64, tiled: bool, pitch: u32) -> Option<u32> {
for i in 0..32 {
if self.registers[i].is_none() {
self.registers[i] = Some(FenceReg { handle, start, size, tiled, pitch });
return Some(i as u32);
}
}
None
}
pub fn release(&mut self, reg: u32) -> Result<()> {
if (reg as usize) < 32 { self.registers[reg as usize] = None; }
Ok(())
}
pub fn get(&self, reg: u32) -> Option<&FenceReg> {
self.registers.get(reg as usize).and_then(|r| r.as_ref())
}
pub fn used_count(&self) -> u32 {
self.registers.iter().filter(|r| r.is_some()).count() as u32
}
pub fn find_by_handle(&self, handle: u32) -> Option<u32> {
for (i, reg) in self.registers.iter().enumerate() {
if let Some(r) = reg { if r.handle == handle { return Some(i as u32); } }
}
None
}
}
pub struct FrameBufferCompressionState {
active_buffers: std::collections::BTreeMap<u32, FbcBuffer>,
compressed_bytes: u64,
}
#[derive(Clone, Debug)]
pub struct FbcBuffer {
pub gem_handle: u32,
pub width: u16,
pub height: u16,
pub stride: u32,
pub compressed: bool,
pub cfb_offset: u64,
pub cfb_size: u64,
}
impl FrameBufferCompressionState {
pub fn new() -> Self {
Self { active_buffers: std::collections::BTreeMap::new(), compressed_bytes: 0 }
}
pub fn register(&mut self, handle: u32, width: u16, height: u16, stride: u32) {
self.active_buffers.insert(handle, FbcBuffer {
gem_handle: handle, width, height, stride,
compressed: false, cfb_offset: 0, cfb_size: 0,
});
}
pub fn unregister(&mut self, handle: u32) {
self.active_buffers.remove(&handle);
}
pub fn mark_compressed(&mut self, handle: u32, cfb_offset: u64, cfb_size: u64) {
if let Some(buf) = self.active_buffers.get_mut(&handle) {
buf.compressed = true;
buf.cfb_offset = cfb_offset;
buf.cfb_size = cfb_size;
self.compressed_bytes += cfb_size;
}
}
pub fn mark_uncompressed(&mut self, handle: u32) {
if let Some(buf) = self.active_buffers.get_mut(&handle) {
if buf.compressed {
self.compressed_bytes -= buf.cfb_size;
buf.compressed = false;
}
}
}
pub fn is_compressed(&self, handle: u32) -> bool {
self.active_buffers.get(&handle).map_or(false, |b| b.compressed)
}
pub fn compressed_bytes(&self) -> u64 { self.compressed_bytes }
pub fn active_count(&self) -> usize { self.active_buffers.len() }
}
@@ -13,6 +13,7 @@ pub mod gem_object;
pub mod gem_pages;
pub mod gem_region;
pub mod gem_request;
pub mod gem_state;
pub mod gem_stolen;
pub mod gem_tiling;
pub mod gem_ttm;
@@ -33,6 +34,7 @@ pub use gem_object::{CacheLevel, GemHandle, GemObject, GemObjectManager, MemoryR
pub use gem_pages::{PageManager, TtmMoveManager};
pub use gem_region::MemoryRegion;
pub use gem_request::{EngineClass, GemRequest, GemStatistics, RequestManager, Scheduler};
pub use gem_state::{FbcBuffer, FenceReg, FenceRegisterState, FrameBufferCompressionState, RenderState};
pub use gem_stolen::{ShrinkerManager, StolenMemoryManager};
pub use gem_tiling::{FenceRegisterManager, TilingConfig, TilingManager, TilingMode};
pub use gem_ttm::{Migration, PowerManager, TtmManager};