1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-20 19:27:22 +03:00

x11: improve support for non-24bpp displays

While looking into what it might take to support 10bpc (30bpp) displays
(https://github.com/wez/wezterm/issues/240) I was experimenting with
Xephyr at a reduced 16bpp depth and noticed that the server still
offered a 32bpp TrueColor depth option.

This commit adjusts the window/bitmap code to allow it to select depths
24bpp or 32bpp, preferring the largest depth.  we restrict ourselves to
24 and 32 bit selections for this, as those appear to be bit for bit
compatible for the r/g/b channels.  I suspect that 10bpc will require
some scaling somewhere.

This change allows running wezterm against the reduced depth Xephyr, but
since Xephyr doesn't support GL it runs with the software renderer; I
don't know quite how opengl is going to play with this.  I can confirm
that running wezterm on my native 24bpp display when it picks a 32bpp
visual does run with opengl enabled, so maybe this is good enough?
This commit is contained in:
Wez Furlong 2020-07-05 10:58:18 -07:00
parent 573f2435c8
commit 627a1c6c1b
3 changed files with 80 additions and 30 deletions

View File

@ -1,6 +1,6 @@
use super::*;
use crate::bitmaps::*;
use anyhow::bail;
use anyhow::{bail, Context as _};
use std::rc::Rc;
/// The X protocol allows referencing a number of drawable
@ -77,7 +77,7 @@ impl Context {
dest_x,
dest_y,
0,
24,
self.conn.depth,
pixel_slice,
)
}
@ -179,7 +179,9 @@ impl ShmImage {
// Tell the server to attach to it
let seg_id = conn.generate_id();
xcb::shm::attach_checked(conn, seg_id, id.id as u32, false).request_check()?;
xcb::shm::attach_checked(conn, seg_id, id.id as u32, false)
.request_check()
.context("xcb::shm::attach_checked")?;
// Now create a pixmap that references it
let draw_id = conn.generate_id();
@ -189,11 +191,12 @@ impl ShmImage {
drawable,
width as u16,
height as u16,
24,
conn.depth,
seg_id,
0,
)
.request_check()?;
.request_check()
.context("create_pixmap_checked")?;
Ok(ShmImage {
data,

View File

@ -4,7 +4,7 @@ use crate::os::x11::window::XWindowInner;
use crate::os::Connection;
use crate::spawn::*;
use crate::timerlist::{TimerEntry, TimerList};
use anyhow::{anyhow, bail};
use anyhow::{anyhow, bail, Context as _};
use mio::unix::EventedFd;
use mio::{Evented, Events, Poll, PollOpt, Ready, Token};
use std::cell::RefCell;
@ -33,6 +33,7 @@ pub struct XConnection {
pub(crate) shm_available: bool,
timers: RefCell<TimerList>,
pub(crate) visual: xcb::xproto::Visualtype,
pub(crate) depth: u8,
}
impl std::ops::Deref for XConnection {
@ -349,18 +350,44 @@ impl XConnection {
.nth(screen_num as usize)
.ok_or_else(|| anyhow!("no screen?"))?;
let visual = screen
.allowed_depths()
.filter(|depth| depth.depth() == 24)
.flat_map(|depth| depth.visuals())
.filter(|vis| vis.class() == xcb::xproto::VISUAL_CLASS_TRUE_COLOR as _)
.nth(0)
.ok_or_else(|| anyhow!("did not find 24-bit visual"))?;
let mut visuals = vec![];
for depth in screen.allowed_depths() {
let depth_bpp = depth.depth();
if depth_bpp == 24 || depth_bpp == 32 {
for vis in depth.visuals() {
if vis.class() == xcb::xproto::VISUAL_CLASS_TRUE_COLOR as _
&& vis.bits_per_rgb_value() == 8
{
visuals.push((depth_bpp, vis));
}
}
}
}
if visuals.is_empty() {
bail!("no suitable visuals of depth 24 or 32 are available");
}
visuals.sort_by(|(a_depth, _), (b_depth, _)| b_depth.cmp(&a_depth));
let (depth, visual) = visuals[0];
log::info!(
"picked depth {} visual id:0x{:x}, class:{}, bits_per_rgb_value:{}, \
colormap entries:{}, masks: r=0x{:x},g=0x{:x},b=0x{:x}",
depth,
visual.visual_id(),
visual.class(),
visual.bits_per_rgb_value(),
visual.colormap_entries(),
visual.red_mask(),
visual.green_mask(),
visual.blue_mask()
);
let (keyboard, kbd_ev) = Keyboard::new(&conn)?;
let cursor_font_id = conn.generate_id();
let cursor_font_name = "cursor";
xcb::open_font_checked(&conn, cursor_font_id, cursor_font_name);
xcb::open_font_checked(&conn, cursor_font_id, cursor_font_name)
.request_check()
.context("xcb::open_font_checked")?;
let conn = XConnection {
display,
@ -380,6 +407,7 @@ impl XConnection {
should_terminate: RefCell::new(false),
shm_available,
timers: RefCell::new(TimerList::new()),
depth,
visual,
};

View File

@ -8,7 +8,7 @@ use crate::{
MousePress, Operator, PaintContext, Point, Rect, ScreenPoint, Size, WindowCallbacks, WindowOps,
WindowOpsMut,
};
use anyhow::anyhow;
use anyhow::{anyhow, Context as _};
use promise::{Future, Promise};
use std::any::Any;
use std::collections::{HashMap, VecDeque};
@ -701,9 +701,20 @@ impl XWindow {
window_id = conn.conn().generate_id();
let color_map_id = conn.conn().generate_id();
xcb::create_colormap_checked(
conn.conn(),
xcb::COLORMAP_ALLOC_NONE as _,
color_map_id,
screen.root(),
conn.visual.visual_id(),
)
.request_check()
.context("create_colormap_checked")?;
xcb::create_window_checked(
conn.conn(),
xcb::COPY_FROM_PARENT as u8,
conn.depth,
window_id,
screen.root(),
// x, y
@ -716,21 +727,29 @@ impl XWindow {
0,
xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
conn.visual.visual_id(), // screen.root_visual(),
&[(
xcb::CW_EVENT_MASK,
xcb::EVENT_MASK_EXPOSURE
| xcb::EVENT_MASK_FOCUS_CHANGE
| xcb::EVENT_MASK_KEY_PRESS
| xcb::EVENT_MASK_BUTTON_PRESS
| xcb::EVENT_MASK_BUTTON_RELEASE
| xcb::EVENT_MASK_POINTER_MOTION
| xcb::EVENT_MASK_BUTTON_MOTION
| xcb::EVENT_MASK_KEY_RELEASE
| xcb::EVENT_MASK_PROPERTY_CHANGE
| xcb::EVENT_MASK_STRUCTURE_NOTIFY,
)],
&[
(
xcb::CW_EVENT_MASK,
xcb::EVENT_MASK_EXPOSURE
| xcb::EVENT_MASK_FOCUS_CHANGE
| xcb::EVENT_MASK_KEY_PRESS
| xcb::EVENT_MASK_BUTTON_PRESS
| xcb::EVENT_MASK_BUTTON_RELEASE
| xcb::EVENT_MASK_POINTER_MOTION
| xcb::EVENT_MASK_BUTTON_MOTION
| xcb::EVENT_MASK_KEY_RELEASE
| xcb::EVENT_MASK_PROPERTY_CHANGE
| xcb::EVENT_MASK_STRUCTURE_NOTIFY,
),
// We have to specify both a border pixel color and a colormap
// when specifying a depth that doesn't match the root window in
// order to avoid a BadMatch
(xcb::CW_BORDER_PIXEL, 0),
(xcb::CW_COLORMAP, color_map_id),
],
)
.request_check()?;
.request_check()
.context("xcb::create_window_checked")?;
let window_context = Context::new(&conn, &window_id);