Skip to content

Commit

Permalink
metal: allow configuring framebuffer formats
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Sep 4, 2024
1 parent ef6106d commit b241ca3
Show file tree
Hide file tree
Showing 24 changed files with 713 additions and 58 deletions.
6 changes: 5 additions & 1 deletion jay-config/src/_private/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use {
timer::Timer,
video::{
connector_type::{ConnectorType, CON_UNKNOWN},
Connector, DrmDevice, GfxApi, Mode, TearingMode, Transform, VrrMode,
Connector, DrmDevice, Format, GfxApi, Mode, TearingMode, Transform, VrrMode,
},
Axis, Direction, ModifiedKeySym, PciId, Workspace,
},
Expand Down Expand Up @@ -754,6 +754,10 @@ impl Client {
self.send(&ClientMessage::ConnectorSetScale { connector, scale });
}

pub fn connector_set_format(&self, connector: Connector, format: Format) {
self.send(&ClientMessage::ConnectorSetFormat { connector, format });
}

pub fn connector_get_scale(&self, connector: Connector) -> f64 {
let res = self.send_with_response(&ClientMessage::ConnectorGetScale { connector });
get_response!(res, 1.0, ConnectorGetScale { scale });
Expand Down
8 changes: 6 additions & 2 deletions jay-config/src/_private/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use {
theme::{colors::Colorable, sized::Resizable, Color},
timer::Timer,
video::{
connector_type::ConnectorType, Connector, DrmDevice, GfxApi, TearingMode, Transform,
VrrMode,
connector_type::ConnectorType, Connector, DrmDevice, Format, GfxApi, TearingMode,
Transform, VrrMode,
},
Axis, Direction, PciId, Workspace,
_private::{PollableId, WireMode},
Expand Down Expand Up @@ -509,6 +509,10 @@ pub enum ClientMessage<'a> {
SetEiSocketEnabled {
enabled: bool,
},
ConnectorSetFormat {
connector: Connector,
format: Format,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
40 changes: 40 additions & 0 deletions jay-config/src/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@ impl Connector {
pub fn set_tearing_mode(self, mode: TearingMode) {
get!().set_tearing_mode(Some(self), mode)
}

/// Sets the format to use for framebuffers.
pub fn set_format(self, format: Format) {
get!().connector_set_format(self, format);
}
}

/// Returns all available DRM devices.
Expand Down Expand Up @@ -612,3 +617,38 @@ impl TearingMode {
pub fn set_tearing_mode(mode: TearingMode) {
get!().set_tearing_mode(None, mode)
}

/// A graphics format.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Format(pub u32);

impl Format {
pub const ARGB8888: Self = Self(0);
pub const XRGB8888: Self = Self(1);
pub const ABGR8888: Self = Self(2);
pub const XBGR8888: Self = Self(3);
pub const R8: Self = Self(4);
pub const GR88: Self = Self(5);
pub const RGB888: Self = Self(6);
pub const BGR888: Self = Self(7);
pub const RGBA4444: Self = Self(8);
pub const RGBX4444: Self = Self(9);
pub const BGRA4444: Self = Self(10);
pub const BGRX4444: Self = Self(11);
pub const RGB565: Self = Self(12);
pub const BGR565: Self = Self(13);
pub const RGBA5551: Self = Self(14);
pub const RGBX5551: Self = Self(15);
pub const BGRA5551: Self = Self(16);
pub const BGRX5551: Self = Self(17);
pub const ARGB1555: Self = Self(18);
pub const XRGB1555: Self = Self(19);
pub const ARGB2101010: Self = Self(20);
pub const XRGB2101010: Self = Self(21);
pub const ABGR2101010: Self = Self(22);
pub const XBGR2101010: Self = Self(23);
pub const ABGR16161616: Self = Self(24);
pub const XBGR16161616: Self = Self(25);
pub const ABGR16161616F: Self = Self(26);
pub const XBGR16161616F: Self = Self(27);
}
5 changes: 5 additions & 0 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use {
async_engine::SpawnedFuture,
drm_feedback::DrmFeedback,
fixed::Fixed,
format::Format,
gfx_api::{GfxFramebuffer, SyncFile},
ifs::{
wl_output::OutputId,
Expand Down Expand Up @@ -116,6 +117,9 @@ pub trait Connector {
fn set_tearing_enabled(&self, enabled: bool) {
let _ = enabled;
}
fn set_fb_format(&self, format: &'static Format) {
let _ = format;
}
}

#[derive(Debug)]
Expand All @@ -128,6 +132,7 @@ pub enum ConnectorEvent {
Unavailable,
Available,
VrrChanged(bool),
FormatsChanged(Rc<Vec<&'static Format>>, &'static Format),
}

pub trait HardwareCursor: Debug {
Expand Down
132 changes: 113 additions & 19 deletions src/backends/metal/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ pub struct MetalDrmDeviceData {
pub struct PersistentDisplayData {
pub mode: RefCell<Option<DrmModeInfo>>,
pub vrr_requested: Cell<bool>,
pub format: Cell<&'static Format>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -415,6 +416,7 @@ pub struct MetalConnector {

pub connector_id: ConnectorId,

pub buffer_format: Cell<&'static Format>,
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
pub next_buffer: NumCell<usize>,

Expand Down Expand Up @@ -460,6 +462,7 @@ pub struct MetalConnector {
pub direct_scanout_active: Cell<bool>,

pub tearing_requested: Cell<bool>,
pub try_switch_format: Cell<bool>,
}

impl Debug for MetalConnector {
Expand Down Expand Up @@ -641,6 +644,25 @@ impl MetalConnector {
}
}

fn send_formats(&self) {
match self.frontend_state.get() {
FrontState::Removed
| FrontState::Disconnected
| FrontState::Unavailable
| FrontState::Connected { non_desktop: true } => return,
FrontState::Connected { non_desktop: false } => {}
}
let mut formats = vec![];
if let Some(plane) = self.primary_plane.get() {
formats = plane.formats.values().map(|f| f.format).collect();
}
let formats = Rc::new(formats);
self.send_event(ConnectorEvent::FormatsChanged(
formats,
self.buffer_format.get(),
));
}

fn send_hardware_cursor(self: &Rc<Self>) {
match self.frontend_state.get() {
FrontState::Removed
Expand Down Expand Up @@ -1264,6 +1286,17 @@ impl MetalConnector {
log::error!("Tried to send vrr-changed event in invalid state: {state:?}");
}
},
ConnectorEvent::FormatsChanged(_, _) => match state {
FrontState::Connected { non_desktop: false } => {
self.on_change.send_event(event);
}
FrontState::Connected { non_desktop: true }
| FrontState::Removed
| FrontState::Disconnected
| FrontState::Unavailable => {
log::error!("Tried to send format-changed event in invalid state: {state:?}");
}
},
}
}
}
Expand Down Expand Up @@ -1425,6 +1458,24 @@ impl Connector for MetalConnector {
log::debug!("{msg} tearing on output {}", self.kernel_id());
}
}

fn set_fb_format(&self, format: &'static Format) {
{
let dd = self.display.borrow().persistent.clone();
dd.format.set(format);
if format == self.buffer_format.get() {
self.try_switch_format.set(false);
return;
}
self.try_switch_format.set(true);
}
if let Some(dev) = self.backend.device_holder.drm_devices.get(&self.dev.devnum) {
if let Err(e) = self.backend.handle_drm_change_(&dev, true) {
dev.unprocessed_change.set(true);
log::error!("Could not change format: {}", ErrorFmt(e));
}
}
}
}

pub struct MetalCrtc {
Expand Down Expand Up @@ -1544,6 +1595,7 @@ fn create_connector(
dev: dev.clone(),
backend: backend.clone(),
connector_id: backend.state.connector_ids.next(),
buffer_format: Cell::new(XRGB8888),
buffers: Default::default(),
next_buffer: Default::default(),
enabled: Cell::new(true),
Expand Down Expand Up @@ -1576,6 +1628,7 @@ fn create_connector(
direct_scanout_active: Cell::new(false),
next_flip_nsec: Cell::new(0),
tearing_requested: Cell::new(false),
try_switch_format: Cell::new(false),
});
let futures = ConnectorFutures {
_present: backend
Expand Down Expand Up @@ -1686,6 +1739,7 @@ fn create_connector_display_data(
let ds = Rc::new(PersistentDisplayData {
mode: RefCell::new(info.modes.first().cloned()),
vrr_requested: Default::default(),
format: Cell::new(XRGB8888),
});
dev.backend
.persistent_display_data
Expand Down Expand Up @@ -2043,6 +2097,7 @@ impl MetalBackend {
};
let mut old = c.display.borrow_mut();
mem::swap(old.deref_mut(), &mut dd);
let mut preserve_connector = false;
match c.frontend_state.get() {
FrontState::Removed | FrontState::Disconnected => {}
FrontState::Connected { .. } | FrontState::Unavailable => {
Expand Down Expand Up @@ -2074,10 +2129,16 @@ impl MetalBackend {
}
c.send_event(ConnectorEvent::Disconnected);
} else if preserve_any {
preserve.connectors.insert(c.id);
preserve_connector = true;
}
}
}
if c.try_switch_format.get() && old.persistent.format.get() != c.buffer_format.get() {
preserve_connector = false;
}
if preserve_connector {
preserve.connectors.insert(c.id);
}
}
for c in new_connectors {
let (connector, future) = match create_connector(self, c, &dev.dev) {
Expand Down Expand Up @@ -2131,6 +2192,7 @@ impl MetalBackend {
}));
connector.send_hardware_cursor();
connector.send_vrr_enabled();
connector.send_formats();
}

pub fn create_drm_device(
Expand Down Expand Up @@ -2662,6 +2724,7 @@ impl MetalBackend {
connector.send_hardware_cursor();
connector.send_vrr_enabled();
connector.update_drm_feedback();
connector.send_formats();
}
Ok(())
}
Expand Down Expand Up @@ -2954,7 +3017,7 @@ impl MetalBackend {
ctx: &MetalRenderContext,
old_buffers: &mut Vec<Rc<dyn Any>>,
) -> Result<(), MetalError> {
let dd = connector.display.borrow_mut();
let dd = &mut *connector.display.borrow_mut();
let crtc = match connector.crtc.get() {
Some(c) => c,
_ => return Ok(()),
Expand All @@ -2966,26 +3029,55 @@ impl MetalBackend {
return Ok(());
}
};
let (primary_plane, primary_modifiers) = 'primary_plane: {
for plane in crtc.possible_planes.values() {
if plane.ty == PlaneType::Primary && !plane.assigned.get() && plane.lease.is_none()
{
if let Some(format) = plane.formats.get(&XRGB8888.drm) {
break 'primary_plane (plane.clone(), &format.modifiers);
let allocate_primary_plane = |format: &'static Format| {
let (primary_plane, primary_modifiers) = 'primary_plane: {
for plane in crtc.possible_planes.values() {
if plane.ty == PlaneType::Primary
&& !plane.assigned.get()
&& plane.lease.is_none()
{
if let Some(format) = plane.formats.get(&format.drm) {
break 'primary_plane (plane.clone(), &format.modifiers);
}
}
}
}
return Err(MetalError::NoPrimaryPlaneForConnector);
return Err(MetalError::NoPrimaryPlaneForConnector);
};
let buffers = Rc::new(self.create_scanout_buffers(
&connector.dev,
format,
primary_modifiers,
mode.hdisplay as _,
mode.vdisplay as _,
ctx,
false,
)?);
Ok((primary_plane, buffers))
};
let buffers = Rc::new(self.create_scanout_buffers(
&connector.dev,
XRGB8888,
primary_modifiers,
mode.hdisplay as _,
mode.vdisplay as _,
ctx,
false,
)?);
let primary_plane;
let buffers;
let buffer_format;
'primary_plane: {
let format = dd.persistent.format.get();
if format != XRGB8888 {
match allocate_primary_plane(format) {
Ok(v) => {
(primary_plane, buffers) = v;
buffer_format = format;
break 'primary_plane;
}
Err(e) => {
log::error!(
"Could not allocate framebuffer with requested format {}: {}",
format.name,
ErrorFmt(e)
);
}
}
}
(primary_plane, buffers) = allocate_primary_plane(XRGB8888)?;
buffer_format = XRGB8888;
}
let mut cursor_plane = None;
let mut cursor_modifiers = &IndexSet::new();
for plane in crtc.possible_planes.values() {
Expand Down Expand Up @@ -3060,6 +3152,8 @@ impl MetalBackend {
}
connector.cursor_plane.set(cursor_plane);
connector.cursor_enabled.set(false);
connector.buffer_format.set(buffer_format);
connector.try_switch_format.set(false);
Ok(())
}

Expand Down
13 changes: 12 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ use {
crate::{
cli::{damage_tracking::DamageTrackingArgs, input::InputArgs, randr::RandrArgs},
compositor::start_compositor,
format::{ref_formats, Format},
portal,
},
::log::Level,
clap::{Args, Parser, Subcommand, ValueEnum},
clap::{builder::PossibleValue, Args, Parser, Subcommand, ValueEnum},
clap_complete::Shell,
};

Expand Down Expand Up @@ -231,6 +232,16 @@ pub struct GenerateArgs {
shell: Shell,
}

impl ValueEnum for &'static Format {
fn value_variants<'a>() -> &'a [Self] {
ref_formats()
}

fn to_possible_value(&self) -> Option<PossibleValue> {
Some(PossibleValue::new(self.name))
}
}

pub fn main() {
let cli = Jay::parse();
match cli.command {
Expand Down
Loading

0 comments on commit b241ca3

Please sign in to comment.