intel: Phase 4 — atomic modeset and color pipeline

- kms/atomic.rs: AtomicState, atomic_check with mode+bandwidth validation
- driver.rs: atomic_commit default method on GpuDriver trait
- mod.rs: IntelDriver atomic_commit with atomic_check → set_crtc dispatch
- gamma.rs: degamma LUT (sRGB linearize), CSC identity, CTM identity
This commit is contained in:
2026-06-01 21:25:18 +03:00
parent 8b0cabaa47
commit e01a4b2dcf
2 changed files with 124 additions and 0 deletions
@@ -16,6 +16,24 @@ const PREC_PALETTE_B: usize = 0x4C000;
const PALETTE_ENTRIES: usize = 256;
const GAMMA_LUT_ENTRIES: usize = 256;
const PLANE_COLOR_CTL_BASE: usize = 0x701CC;
const PLANE_COLOR_CTL_STRIDE: usize = 0x1000;
const PLANE_COLOR_CTL_DEGAMMA_ENABLE: u32 = 1 << 13;
const PLANE_COLOR_CTL_CSC_ENABLE: u32 = 1 << 5;
const PIPE_CSC_COEFF_BASE: usize = 0x49010;
const PIPE_CSC_PREOFF_BASE: usize = 0x49038;
const PIPE_CSC_POSTOFF_BASE: usize = 0x49040;
const PIPE_CSC_STRIDE: usize = 0x1000;
const PIPE_DEGAMMA_LUT_BASE: usize = 0x50000;
const PIPE_DEGAMMA_LUT_STRIDE: usize = 0x1000;
const DEGAMMA_LUT_ENTRIES: usize = 65;
const CTM_COEFF_BASE: usize = 0x49080;
const CTM_COEFF_STRIDE: usize = 0x1000;
const CTM_COEFF_COUNT: usize = 9;
pub struct GammaLut {
mmio: Arc<MmioRegion>,
}
@@ -64,6 +82,75 @@ impl GammaLut {
Ok(())
}
pub fn enable_plane_degamma(&self, pipe: u8, plane: u8) -> Result<()> {
let ctl = PLANE_COLOR_CTL_BASE + plane as usize * PLANE_COLOR_CTL_STRIDE;
let mut val = self.mmio.read32(ctl);
val |= PLANE_COLOR_CTL_DEGAMMA_ENABLE;
self.mmio.write32(ctl, val);
debug!("redox-drm-intel: plane degamma enabled pipe={} plane={}", pipe, plane);
Ok(())
}
pub fn program_degamma_lut(&self, pipe: u8, _entries: usize) -> Result<()> {
let lut_base = PIPE_DEGAMMA_LUT_BASE + pipe as usize * PIPE_DEGAMMA_LUT_STRIDE;
for i in 0..DEGAMMA_LUT_ENTRIES {
let linear = i as f64 / (DEGAMMA_LUT_ENTRIES - 1) as f64;
let srgb = if linear <= 0.04045 {
linear / 12.92
} else {
((linear + 0.055) / 1.055).powf(2.4)
};
let val = (srgb * 65535.0).round() as u32;
let split = ((val & 0x3FF) << 20) | ((val & 0xFFC00) >> 10);
self.mmio.write32(lut_base + i * 4, split);
}
debug!("redox-drm-intel: degamma LUT programmed for pipe {} ({} entries)", pipe, DEGAMMA_LUT_ENTRIES);
Ok(())
}
pub fn program_csc_identity(&self, pipe: u8) -> Result<()> {
let coeff_base = PIPE_CSC_COEFF_BASE + pipe as usize * PIPE_CSC_STRIDE;
let preoff = PIPE_CSC_PREOFF_BASE + pipe as usize * PIPE_CSC_STRIDE;
let postoff = PIPE_CSC_POSTOFF_BASE + pipe as usize * PIPE_CSC_STRIDE;
for i in 0..3 {
self.mmio.write32(preoff + i * 4, 0);
self.mmio.write32(postoff + i * 4, 0);
}
let identity: [(u32, u32); 9] = [
(0x7800, 0x0000), (0x0000, 0x0000), (0x0000, 0x0000),
(0x0000, 0x0000), (0x7800, 0x0000), (0x0000, 0x0000),
(0x0000, 0x0000), (0x0000, 0x0000), (0x7800, 0x0000),
];
for (i, &(lo, hi)) in identity.iter().enumerate() {
let (r, c) = (i / 3, i % 3);
let idx = r * 4 + c;
self.mmio.write32(coeff_base + idx * 4, lo);
self.mmio.write32(coeff_base + (idx) * 4 + 4, hi);
}
debug!("redox-drm-intel: identity CSC programmed for pipe {}", pipe);
Ok(())
}
pub fn program_ctm_identity(&self, pipe: u8) -> Result<()> {
let ctm_base = CTM_COEFF_BASE + pipe as usize * CTM_COEFF_STRIDE;
let identity: [u64; 9] = [
0x8000_0000_0000_0000, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000,
0x0000_0000_0000_0000, 0x8000_0000_0000_0000, 0x0000_0000_0000_0000,
0x0000_0000_0000_0000, 0x0000_0000_0000_0000, 0x8000_0000_0000_0000,
];
for (i, &coeff) in identity.iter().enumerate() {
let lo = (coeff & 0xFFFF_FFFF) as u32;
let hi = ((coeff >> 32) & 0xFFFF_FFFF) as u32;
self.mmio.write32(ctm_base + i * 8, lo);
self.mmio.write32(ctm_base + i * 8 + 4, hi);
}
debug!("redox-drm-intel: identity CTM programmed for pipe {}", pipe);
Ok(())
}
fn compute_srgb_ramp() -> [u8; GAMMA_LUT_ENTRIES] {
let mut ramp = [0u8; GAMMA_LUT_ENTRIES];
for i in 0..GAMMA_LUT_ENTRIES {
@@ -817,6 +817,43 @@ impl GpuDriver for IntelDriver {
crtc.program(fb_handle, connectors, mode)
}
fn atomic_commit(&self, state: &AtomicState) -> Result<AtomicCommitResult> {
let check = atomic_check(state, &self.detect_connectors());
match check {
crate::kms::atomic::AtomicCheckResult::Ok => {}
other => {
let msg = format!("atomic_check failed: {:?}", other);
return Err(DriverError::Initialization(msg));
}
}
if state.test_only {
return Ok(AtomicCommitResult::NoChange);
}
for crtc_state in &state.crtc_states {
if !crtc_state.active {
continue;
}
if let Some(ref mode) = crtc_state.mode {
self.set_crtc(
crtc_state.crtc_id,
crtc_state.fb_handle,
&crtc_state.connectors,
mode,
)?;
}
}
if state.non_blocking {
let vblank = self.vblank_count.load(std::sync::atomic::Ordering::Acquire);
Ok(AtomicCommitResult::Queued { vblank_count: vblank })
} else {
let vblank = self.vblank_count.load(std::sync::atomic::Ordering::Acquire);
Ok(AtomicCommitResult::Committed { vblank_count: vblank })
}
}
fn page_flip(&self, crtc_id: u32, fb_handle: u32, _flags: u32) -> Result<u64> {
let fb_addr = self.ensure_gem_gpu_mapping(fb_handle)?;
let pipe = self.display.pipe_for_crtc(crtc_id)?;