Add output configuration & integer scaling support

This commit is contained in:
Ivan Molodetskikh
2023-09-21 13:48:32 +04:00
parent cfa73c153c
commit 109668fa30
6 changed files with 101 additions and 24 deletions
+8
View File
@@ -27,6 +27,14 @@ input {
}
}
// You can configure outputs by their name, which you can find with wayland-info(1).
// The built-in laptop monitor is usually called "eDP-1".
// Remember to uncommend the node by removing "/-"!
/-output "eDP-1" {
// Scale is a floating-point number, but at the moment only integer values work.
scale 2.0
}
binds {
// Keys consist of modifiers separated by + signs, followed by an XKB key name
// in the end. To find an XKB name for a particular key, you may use a program
+14 -2
View File
@@ -21,7 +21,7 @@ use smithay::backend::session::libseat::LibSeatSession;
use smithay::backend::session::{Event as SessionEvent, Session};
use smithay::backend::udev::{self, UdevBackend, UdevEvent};
use smithay::desktop::utils::OutputPresentationFeedback;
use smithay::output::{Mode, Output, OutputModeSource, PhysicalProperties, Subpixel};
use smithay::output::{Mode, Output, OutputModeSource, PhysicalProperties, Subpixel, Scale};
use smithay::reexports::calloop::{Dispatcher, LoopHandle, RegistrationToken};
use smithay::reexports::drm::control::{
connector, crtc, Mode as DrmMode, ModeFlags, ModeTypeFlags,
@@ -500,6 +500,15 @@ impl Tty {
);
debug!("connecting connector: {output_name}");
let config = self
.config
.borrow()
.outputs
.iter()
.find(|o| o.name == output_name)
.cloned()
.unwrap_or_default();
let device = self.output_device.as_mut().unwrap();
let mut mode = connector.modes().get(0);
@@ -534,6 +543,9 @@ impl Tty {
.map(|info| (info.manufacturer, info.model))
.unwrap_or_else(|| ("Unknown".into(), "Unknown".into()));
let scale = config.scale.clamp(0.1, 10.);
let scale = scale.max(1.).round() as i32;
let output = Output::new(
output_name.clone(),
PhysicalProperties {
@@ -544,7 +556,7 @@ impl Tty {
},
);
let wl_mode = Mode::from(*mode);
output.change_current_state(Some(wl_mode), None, None, Some((0, 0).into()));
output.change_current_state(Some(wl_mode), None, Some(Scale::Integer(scale)), None);
output.set_preferred(wl_mode);
output.user_data().insert_if_missing(|| TtyOutputState {
+12 -2
View File
@@ -8,7 +8,7 @@ use smithay::backend::renderer::damage::OutputDamageTracker;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::{DebugFlags, Renderer};
use smithay::backend::winit::{self, WinitError, WinitEvent, WinitGraphicsBackend};
use smithay::output::{Mode, Output, PhysicalProperties, Subpixel};
use smithay::output::{Mode, Output, PhysicalProperties, Scale, Subpixel};
use smithay::reexports::calloop::timer::{TimeoutAction, Timer};
use smithay::reexports::calloop::LoopHandle;
use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback;
@@ -38,6 +38,16 @@ impl Winit {
.with_title("niri");
let (backend, mut winit_event_loop) = winit::init_from_builder(builder).unwrap();
let output_config = config
.borrow()
.outputs
.iter()
.find(|o| o.name == "winit")
.cloned()
.unwrap_or_default();
let scale = output_config.scale.clamp(0.1, 10.);
let scale = scale.max(1.).round() as i32;
let mode = Mode {
size: backend.window_size().physical_size,
refresh: 60_000,
@@ -55,8 +65,8 @@ impl Winit {
output.change_current_state(
Some(mode),
Some(Transform::Flipped180),
Some(Scale::Integer(scale)),
None,
Some((0, 0).into()),
);
output.set_preferred(mode);
+27
View File
@@ -11,6 +11,8 @@ use smithay::input::keyboard::Keysym;
pub struct Config {
#[knuffel(child, default)]
pub input: Input,
#[knuffel(children(name = "output"))]
pub outputs: Vec<Output>,
#[knuffel(child, default)]
pub binds: Binds,
#[knuffel(child, default)]
@@ -62,6 +64,23 @@ pub struct Touchpad {
pub accel_speed: f64,
}
#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
pub struct Output {
#[knuffel(argument)]
pub name: String,
#[knuffel(child, unwrap(argument), default = 1.)]
pub scale: f64,
}
impl Default for Output {
fn default() -> Self {
Self {
name: String::new(),
scale: 1.,
}
}
}
#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
pub struct Binds(#[knuffel(children)] pub Vec<Bind>);
@@ -263,6 +282,10 @@ mod tests {
}
}
output "eDP-1" {
scale 2.0
}
binds {
Mod+T { spawn "alacritty"; }
Mod+Q { close-window; }
@@ -293,6 +316,10 @@ mod tests {
accel_speed: 0.2,
},
},
outputs: vec![Output {
name: "eDP-1".to_owned(),
scale: 2.,
}],
binds: Binds(vec![
Bind {
key: Key {
+16 -7
View File
@@ -1231,6 +1231,7 @@ impl Monitor<Window> {
&self,
renderer: &mut GlesRenderer,
) -> Vec<MonitorRenderElement<GlesRenderer>> {
let output_scale = Scale::from(self.output.current_scale().fractional_scale());
let output_transform = self.output.current_transform();
let output_mode = self.output.current_mode().unwrap();
let output_size = output_transform.transform_size(output_mode.size);
@@ -1251,7 +1252,7 @@ impl Monitor<Window> {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
1.,
output_scale,
Rectangle::from_loc_and_size((0, 0), output_size),
)?,
(0, -offset),
@@ -1262,7 +1263,7 @@ impl Monitor<Window> {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
1.,
output_scale,
Rectangle::from_loc_and_size((0, 0), output_size),
)?,
(0, -offset + output_size.h),
@@ -1279,7 +1280,7 @@ impl Monitor<Window> {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
1.,
output_scale,
Rectangle::from_loc_and_size((0, 0), output_size),
)?,
(0, 0),
@@ -1823,6 +1824,14 @@ impl Workspace<Window> {
return vec![];
}
// FIXME: workspaces should probably cache their last used scale so they can be correctly
// rendered even with no outputs connected.
let output_scale = self
.output
.as_ref()
.map(|o| Scale::from(o.current_scale().fractional_scale()))
.unwrap_or(Scale::from(1.));
let mut rv = vec![];
let view_pos = self.view_pos();
@@ -1840,8 +1849,8 @@ impl Workspace<Window> {
}
rv.extend(active_win.render_elements(
renderer,
win_pos.to_physical(1),
Scale::from(1.),
win_pos.to_physical_precise_round(output_scale),
output_scale,
1.,
));
@@ -1862,8 +1871,8 @@ impl Workspace<Window> {
rv.extend(win.render_elements(
renderer,
win_pos.to_physical(1),
Scale::from(1.),
win_pos.to_physical_precise_round(output_scale),
output_scale,
1.,
));
}
+24 -13
View File
@@ -799,6 +799,7 @@ impl Niri {
renderer: &mut GlesRenderer,
output: &Output,
) -> Vec<OutputRenderElements<GlesRenderer>> {
let output_scale = Scale::from(output.current_scale().fractional_scale());
let output_pos = self.global_space.output_geometry(output).unwrap().loc;
let pointer_pos = self.seat.get_pointer().unwrap().current_location() - output_pos.to_f64();
@@ -825,7 +826,7 @@ impl Niri {
} else {
default_hotspot
};
let pointer_pos = (pointer_pos - hotspot.to_f64()).to_physical_precise_round(1.);
let pointer_pos = (pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
let mut pointer_elements = match &self.cursor_image {
CursorImageStatus::Hidden => vec![],
@@ -843,7 +844,7 @@ impl Niri {
renderer,
surface,
pointer_pos,
1.,
output_scale,
1.,
Kind::Cursor,
),
@@ -854,7 +855,7 @@ impl Niri {
renderer,
dnd_icon,
pointer_pos,
1.,
output_scale,
1.,
Kind::Unspecified,
));
@@ -871,6 +872,8 @@ impl Niri {
) -> Vec<OutputRenderElements<GlesRenderer>> {
let _span = tracy_client::span!("Niri::render");
let output_scale = Scale::from(output.current_scale().fractional_scale());
// Get monitor elements.
let mon = self.monitor_set.monitor_for_output(output).unwrap();
let monitor_elements = mon.render_elements(renderer);
@@ -901,8 +904,8 @@ impl Niri {
surface
.render_elements(
renderer,
loc.to_physical_precise_round(1.),
Scale::from(1.),
loc.to_physical_precise_round(output_scale),
output_scale,
1.,
)
.into_iter()
@@ -926,8 +929,8 @@ impl Niri {
surface
.render_elements(
renderer,
loc.to_physical_precise_round(1.),
Scale::from(1.),
loc.to_physical_precise_round(output_scale),
output_scale,
1.,
)
.into_iter()
@@ -1084,6 +1087,7 @@ impl Niri {
let _span = tracy_client::span!("Niri::send_for_screen_cast");
let size = output.current_mode().unwrap().size;
let scale = Scale::from(output.current_scale().fractional_scale());
for cast in &mut self.casts {
if !cast.is_active.get() {
@@ -1119,7 +1123,7 @@ impl Niri {
let dmabuf = cast.dmabufs.borrow()[&fd].clone();
// FIXME: Hidden / embedded / metadata cursor
render_to_dmabuf(backend.renderer(), dmabuf, size, elements).unwrap();
render_to_dmabuf(backend.renderer(), dmabuf, size, scale, elements).unwrap();
let maxsize = data.as_raw().maxsize;
let chunk = data.chunk_mut();
@@ -1139,8 +1143,9 @@ impl Niri {
let _span = tracy_client::span!("Niri::screenshot");
let size = output.current_mode().unwrap().size;
let scale = Scale::from(output.current_scale().fractional_scale());
let elements = self.render(renderer, output, true);
let pixels = render_to_vec(renderer, size, &elements)?;
let pixels = render_to_vec(renderer, size, scale, &elements)?;
let path = make_screenshot_path().context("error making screenshot path")?;
debug!("saving screenshot to {path:?}");
@@ -1174,6 +1179,7 @@ impl Niri {
let outputs: Vec<_> = self.global_space.outputs().cloned().collect();
for output in outputs {
let geom = self.global_space.output_geometry(&output).unwrap();
// FIXME: this does not work when outputs can have non-1 scale.
let geom = geom.to_physical(1);
size.w = max(size.w, geom.loc.x + geom.size.w);
@@ -1185,7 +1191,8 @@ impl Niri {
}));
}
let pixels = render_to_vec(renderer, size, &elements)?;
// FIXME: scale.
let pixels = render_to_vec(renderer, size, Scale::from(1.), &elements)?;
let path = make_screenshot_path().context("error making screenshot path")?;
debug!("saving screenshot to {path:?}");
@@ -1232,6 +1239,7 @@ impl ClientData for ClientState {
fn render_and_download(
renderer: &mut GlesRenderer,
size: Size<i32, Physical>,
scale: Scale<f64>,
elements: &[impl RenderElement<GlesRenderer>],
) -> anyhow::Result<GlesMapping> {
let _span = tracy_client::span!("render_and_download");
@@ -1255,7 +1263,7 @@ fn render_and_download(
for element in elements.iter().rev() {
let src = element.src();
let dst = element.geometry(Scale::from(1.));
let dst = element.geometry(scale);
element
.draw(&mut frame, src, dst, &[output_rect])
.context("error drawing element")?;
@@ -1273,11 +1281,13 @@ fn render_and_download(
fn render_to_vec(
renderer: &mut GlesRenderer,
size: Size<i32, Physical>,
scale: Scale<f64>,
elements: &[impl RenderElement<GlesRenderer>],
) -> anyhow::Result<Vec<u8>> {
let _span = tracy_client::span!("render_to_vec");
let mapping = render_and_download(renderer, size, elements).context("error rendering")?;
let mapping =
render_and_download(renderer, size, scale, elements).context("error rendering")?;
let copy = renderer
.map_texture(&mapping)
.context("error mapping texture")?;
@@ -1288,6 +1298,7 @@ fn render_to_dmabuf(
renderer: &mut GlesRenderer,
dmabuf: Dmabuf,
size: Size<i32, Physical>,
scale: Scale<f64>,
elements: &[OutputRenderElements<GlesRenderer>],
) -> anyhow::Result<()> {
let _span = tracy_client::span!("render_to_dmabuf");
@@ -1305,7 +1316,7 @@ fn render_to_dmabuf(
for element in elements.iter().rev() {
let src = element.src();
let dst = element.geometry(Scale::from(1.));
let dst = element.geometry(scale);
element
.draw(&mut frame, src, dst, &[output_rect])
.context("error drawing element")?;