1
0
Fork 0
forked from wry/wry
wry/src/backends/metal/video/model.rs

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()
}
}