364 lines
10 KiB
Rust
364 lines
10 KiB
Rust
use {
|
|
super::{copy_device::CopyDeviceHolder, lease::MetalLeaseData, properties::DefaultProperty},
|
|
crate::{
|
|
async_engine::SpawnedFuture,
|
|
backend::{
|
|
BackendConnectorState, BackendLuminance, ConnectorEvent, ConnectorId,
|
|
ConnectorKernelId, DrmDeviceId, DrmEvent, Mode, OutputId,
|
|
},
|
|
backends::metal::{
|
|
MetalBackend,
|
|
allocator::RenderBuffer,
|
|
present::{DirectScanoutCache, PresentFb},
|
|
transaction::{DrmConnectorState, DrmCrtcState, DrmPlaneState},
|
|
},
|
|
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
|
drm_feedback::DrmFeedback,
|
|
format::Format,
|
|
gfx_api::{FdSync, GfxContext},
|
|
state::State,
|
|
utils::{
|
|
asyncevent::AsyncEvent, binary_search_map::BinarySearchMap, clonecell::CloneCell,
|
|
copyhashmap::CopyHashMap, geometric_decay::GeometricDecay, numcell::NumCell,
|
|
on_change::OnChange, opaque_cell::OpaqueCell,
|
|
},
|
|
video::{
|
|
Modifier,
|
|
dmabuf::DmaBufId,
|
|
drm::{
|
|
ConnectorStatus, DrmConnector, DrmCrtc, DrmEncoder, DrmMaster, DrmModeInfo,
|
|
DrmObject, DrmPlane, DrmProperty,
|
|
},
|
|
gbm::GbmDevice,
|
|
},
|
|
},
|
|
ahash::AHashMap,
|
|
indexmap::IndexSet,
|
|
std::{
|
|
cell::{Cell, RefCell},
|
|
ffi::CString,
|
|
fmt::{Debug, Formatter},
|
|
rc::Rc,
|
|
},
|
|
uapi::c,
|
|
};
|
|
|
|
pub struct PendingDrmDevice {
|
|
pub id: DrmDeviceId,
|
|
pub devnum: c::dev_t,
|
|
pub devnode: CString,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MetalRenderContext {
|
|
pub dev_id: DrmDeviceId,
|
|
pub gfx: Rc<dyn GfxContext>,
|
|
pub gbm: Rc<GbmDevice>,
|
|
pub devnode: CString,
|
|
pub copy_device: Rc<CopyDeviceHolder>,
|
|
}
|
|
|
|
pub struct MetalDrmDevice {
|
|
pub backend: Rc<MetalBackend>,
|
|
pub id: DrmDeviceId,
|
|
pub devnum: c::dev_t,
|
|
pub devnode: CString,
|
|
pub master: Rc<DrmMaster>,
|
|
pub supports_kms: bool,
|
|
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
|
|
pub encoders: AHashMap<DrmEncoder, Rc<MetalEncoder>>,
|
|
pub planes: AHashMap<DrmPlane, Rc<MetalPlane>>,
|
|
pub cursor_width: u64,
|
|
pub cursor_height: u64,
|
|
pub supports_async_commit: bool,
|
|
pub gbm: Rc<GbmDevice>,
|
|
pub handle_events: HandleEvents,
|
|
pub ctx: CloneCell<Rc<MetalRenderContext>>,
|
|
pub copy_device: Rc<CopyDeviceHolder>,
|
|
pub on_change: OnChange<DrmEvent>,
|
|
pub direct_scanout_enabled: Cell<Option<bool>>,
|
|
pub is_nvidia: bool,
|
|
pub _is_amd: bool,
|
|
pub lease_ids: MetalLeaseIds,
|
|
pub leases: CopyHashMap<MetalLeaseId, MetalLeaseData>,
|
|
pub leases_to_break: CopyHashMap<MetalLeaseId, MetalLeaseData>,
|
|
pub paused: Cell<bool>,
|
|
pub min_post_commit_margin: Cell<u64>,
|
|
}
|
|
|
|
impl Debug for MetalDrmDevice {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("MetalDrmDevice").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
impl MetalDrmDevice {
|
|
pub fn is_render_device(&self) -> bool {
|
|
if let Some(ctx) = self.backend.ctx.get() {
|
|
return ctx.dev_id == self.id;
|
|
}
|
|
false
|
|
}
|
|
}
|
|
|
|
pub struct HandleEvents {
|
|
pub handle_events: Cell<Option<SpawnedFuture<()>>>,
|
|
}
|
|
|
|
impl Debug for HandleEvents {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("HandleEvents").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MetalDrmDeviceData {
|
|
pub dev: Rc<MetalDrmDevice>,
|
|
pub connectors: CopyHashMap<DrmConnector, Rc<MetalConnector>>,
|
|
pub futures: CopyHashMap<DrmConnector, ConnectorFutures>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct PersistentDisplayData {
|
|
pub state: RefCell<BackendConnectorState>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ConnectorDisplayData {
|
|
pub crtc_id: DrmProperty,
|
|
pub crtcs: BinarySearchMap<DrmCrtc, Rc<MetalCrtc>, 8>,
|
|
pub first_mode: Mode,
|
|
pub modes: Vec<DrmModeInfo>,
|
|
pub persistent: Rc<PersistentDisplayData>,
|
|
pub refresh: u32,
|
|
pub non_desktop: bool,
|
|
pub non_desktop_effective: bool,
|
|
pub vrr_capable: bool,
|
|
pub _vrr_refresh_max_nsec: u64,
|
|
pub default_properties: Vec<DefaultProperty>,
|
|
pub untyped_properties: AHashMap<DrmProperty, u64>,
|
|
|
|
pub connector_id: ConnectorKernelId,
|
|
pub output_id: Rc<OutputId>,
|
|
|
|
pub connection: ConnectorStatus,
|
|
pub mm_width: u32,
|
|
pub mm_height: u32,
|
|
pub _subpixel: u32,
|
|
|
|
pub supports_bt2020: bool,
|
|
pub supports_pq: bool,
|
|
pub primaries: Primaries,
|
|
pub luminance: Option<BackendLuminance>,
|
|
|
|
pub colorspace: Option<DrmProperty>,
|
|
pub hdr_metadata: Option<DrmProperty>,
|
|
pub drm_state: DrmConnectorState,
|
|
}
|
|
|
|
impl ConnectorDisplayData {
|
|
fn update_refresh(&mut self, dev: &MetalDrmDevice) {
|
|
self.refresh = 0;
|
|
if self.drm_state.crtc_id.is_none() {
|
|
return;
|
|
}
|
|
let Some(crtc) = dev.crtcs.get(&self.drm_state.crtc_id) else {
|
|
return;
|
|
};
|
|
let drm_state = &*crtc.drm_state.borrow();
|
|
let Some(mode) = &drm_state.mode else {
|
|
return;
|
|
};
|
|
let refresh_rate_mhz = mode.refresh_rate_millihz();
|
|
if refresh_rate_mhz != 0 {
|
|
self.refresh = (1_000_000_000_000u64 / refresh_rate_mhz as u64) as u32;
|
|
}
|
|
}
|
|
|
|
fn update_non_desktop_effective(&mut self) {
|
|
let state = &*self.persistent.state.borrow();
|
|
self.non_desktop_effective =
|
|
!state.enabled || state.non_desktop_override.unwrap_or(self.non_desktop);
|
|
}
|
|
|
|
pub fn update_cached_fields(&mut self, dev: &MetalDrmDevice) {
|
|
self.update_refresh(dev);
|
|
self.update_non_desktop_effective();
|
|
}
|
|
}
|
|
|
|
linear_ids!(MetalLeaseIds, MetalLeaseId, u64);
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum FrontState {
|
|
Removed,
|
|
Disconnected,
|
|
Connected { non_desktop: bool },
|
|
Unavailable,
|
|
}
|
|
|
|
pub struct MetalConnector {
|
|
pub id: DrmConnector,
|
|
pub kernel_id: Cell<ConnectorKernelId>,
|
|
pub master: Rc<DrmMaster>,
|
|
pub state: Rc<State>,
|
|
|
|
pub dev: Rc<MetalDrmDevice>,
|
|
pub backend: Rc<MetalBackend>,
|
|
|
|
pub connector_id: ConnectorId,
|
|
|
|
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
|
pub color_description: CloneCell<Rc<ColorDescription>>,
|
|
|
|
pub lease: Cell<Option<MetalLeaseId>>,
|
|
|
|
pub buffers_idle: Cell<bool>,
|
|
pub crtc_idle: Cell<bool>,
|
|
pub has_damage: NumCell<u64>,
|
|
pub cursor_changed: Cell<bool>,
|
|
pub cursor_damage: Cell<bool>,
|
|
pub next_vblank_nsec: Cell<u64>,
|
|
|
|
pub display: RefCell<ConnectorDisplayData>,
|
|
|
|
pub frontend_state: Cell<FrontState>,
|
|
|
|
pub primary_plane: CloneCell<Option<Rc<MetalPlane>>>,
|
|
pub cursor_plane: CloneCell<Option<Rc<MetalPlane>>>,
|
|
|
|
pub crtc: CloneCell<Option<Rc<MetalCrtc>>>,
|
|
|
|
pub on_change: OnChange<ConnectorEvent>,
|
|
|
|
pub present_trigger: AsyncEvent,
|
|
|
|
pub cursor_x: Cell<i32>,
|
|
pub cursor_y: Cell<i32>,
|
|
pub cursor_enabled: Cell<bool>,
|
|
pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
|
pub cursor_swap_buffer: Cell<bool>,
|
|
pub cursor_sync: CloneCell<Option<FdSync>>,
|
|
|
|
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
|
|
pub scanout_buffers: RefCell<AHashMap<DmaBufId, DirectScanoutCache>>,
|
|
pub active_framebuffer: RefCell<Option<PresentFb>>,
|
|
pub next_framebuffer: OpaqueCell<Option<PresentFb>>,
|
|
pub direct_scanout_active: Cell<bool>,
|
|
|
|
pub version: NumCell<u64>,
|
|
pub expected_sequence: Cell<Option<u64>>,
|
|
pub pre_commit_margin: Cell<u64>,
|
|
pub pre_commit_margin_decay: GeometricDecay,
|
|
pub post_commit_margin: Cell<u64>,
|
|
pub post_commit_margin_decay: GeometricDecay,
|
|
pub vblank_miss_sec: Cell<u32>,
|
|
pub vblank_miss_this_sec: NumCell<u32>,
|
|
pub presentation_is_sync: Cell<bool>,
|
|
pub presentation_is_zero_copy: Cell<bool>,
|
|
}
|
|
|
|
impl Debug for MetalConnector {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("MetalConnnector").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
pub struct ConnectorFutures {
|
|
pub _present: SpawnedFuture<()>,
|
|
}
|
|
|
|
impl Debug for ConnectorFutures {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("ConnectorFutures").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
pub struct MetalCrtc {
|
|
pub id: DrmCrtc,
|
|
pub idx: usize,
|
|
pub master: Rc<DrmMaster>,
|
|
pub default_properties: Vec<DefaultProperty>,
|
|
pub untyped_properties: RefCell<AHashMap<DrmProperty, u64>>,
|
|
|
|
pub lease: Cell<Option<MetalLeaseId>>,
|
|
|
|
pub possible_planes: BinarySearchMap<DrmPlane, Rc<MetalPlane>, 8>,
|
|
|
|
pub connector: CloneCell<Option<Rc<MetalConnector>>>,
|
|
pub pending_flip: CloneCell<Option<Rc<MetalConnector>>>,
|
|
|
|
pub active: DrmProperty,
|
|
pub mode_id: DrmProperty,
|
|
pub vrr_enabled: DrmProperty,
|
|
pub out_fence_ptr: DrmProperty,
|
|
pub gamma_lut: Option<DrmProperty>,
|
|
pub gamma_lut_size: Option<u32>,
|
|
pub drm_state: RefCell<DrmCrtcState>,
|
|
|
|
pub sequence: Cell<u64>,
|
|
pub have_queued_sequence: Cell<bool>,
|
|
pub needs_vblank_emulation: Cell<bool>,
|
|
}
|
|
|
|
impl Debug for MetalCrtc {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("MetalCrtc").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MetalEncoder {
|
|
pub id: DrmEncoder,
|
|
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
pub enum PlaneType {
|
|
Overlay,
|
|
Primary,
|
|
Cursor,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct PlaneFormat {
|
|
pub format: &'static Format,
|
|
pub modifiers: IndexSet<Modifier>,
|
|
}
|
|
|
|
pub struct MetalPlane {
|
|
pub id: DrmPlane,
|
|
pub master: Rc<DrmMaster>,
|
|
pub default_properties: Vec<DefaultProperty>,
|
|
pub untyped_properties: RefCell<AHashMap<DrmProperty, u64>>,
|
|
|
|
pub ty: PlaneType,
|
|
|
|
pub possible_crtcs: u32,
|
|
pub formats: AHashMap<u32, PlaneFormat>,
|
|
|
|
pub lease: Cell<Option<MetalLeaseId>>,
|
|
|
|
pub mode_w: Cell<i32>,
|
|
pub mode_h: Cell<i32>,
|
|
|
|
pub crtc_id: DrmProperty,
|
|
pub crtc_x: DrmProperty,
|
|
pub crtc_y: DrmProperty,
|
|
pub crtc_w: DrmProperty,
|
|
pub crtc_h: DrmProperty,
|
|
pub src_x: DrmProperty,
|
|
pub src_y: DrmProperty,
|
|
pub src_w: DrmProperty,
|
|
pub src_h: DrmProperty,
|
|
pub in_fence_fd: DrmProperty,
|
|
pub fb_id: DrmProperty,
|
|
|
|
pub drm_state: RefCell<DrmPlaneState>,
|
|
}
|
|
|
|
impl Debug for MetalPlane {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("MetalPlane").finish_non_exhaustive()
|
|
}
|
|
}
|