Switch to a single GPU context in Blade (#20853)
Closes #17005 Release Notes: - Improved GPU context management: share a single context with multiple surfaces. ### High Level Blade got a proper support for Surface objects in https://github.com/kvark/blade/pull/203. That was mainly motivated by Zed needing to draw multiple windows. With the Surface API, Zed is now able to have the GPU context tied to the "Platform" instead of "Window". Practically speaking, this means: - architecture more sound - faster to open/close windows - less surprises, more robust ### Concerns 1. Zed has been using a temporary workaround for the platform bug on some Intel+Nvidia machines that makes us unable to present - https://github.com/kvark/blade/pull/144 . This workaround is no longer available with the new architecture. I'm looking for ideas on how to approach this better. - we are now picking up the change in https://github.com/kvark/blade/pull/210, which allows forcing a specific Device ID. This should allow Zed users to work around the issue. We could help them to automate it, too. 2. ~~Metal-rs dependency is switched to https://github.com/kvark/metal-rs/tree/blade, since upstream isn't responsive in merging changes that are required for Blade. Hopefully, temporary.~~ - ~~we can also hack around it by just transmuting the texture references, since we know those are unchanged in the branch. That would allow Blade to use it's own version of Metal, temporarily, if switching metal-rs in the workspace is a concern.~~ - merged my metal-rs changes and updated Zed to use the upstream github reference --------- Co-authored-by: Mikayla Maki <mikayla@zed.dev> Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com> Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
co-authored by
Mikayla Maki
Mikayla Maki
Conrad Irwin
parent
56d20fc0a3
commit
298b9df589
@@ -1,52 +1,45 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use std::any::{type_name, Any};
|
||||
use std::cell::{self, RefCell};
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::fd::{AsFd, AsRawFd, FromRawFd};
|
||||
use std::panic::{AssertUnwindSafe, Location};
|
||||
use std::rc::Weak;
|
||||
use std::{
|
||||
env,
|
||||
panic::AssertUnwindSafe,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
fs::File,
|
||||
io::Read as _,
|
||||
os::fd::{AsFd, AsRawFd, FromRawFd},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Context as _};
|
||||
use async_task::Runnable;
|
||||
use calloop::channel::Channel;
|
||||
use calloop::{EventLoop, LoopHandle, LoopSignal};
|
||||
use flume::{Receiver, Sender};
|
||||
use calloop::{channel::Channel, LoopSignal};
|
||||
use futures::{channel::oneshot, future::FutureExt};
|
||||
use parking_lot::Mutex;
|
||||
use util::ResultExt;
|
||||
|
||||
use util::ResultExt as _;
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
use xkbcommon::xkb::{self, Keycode, Keysym, State};
|
||||
|
||||
use crate::platform::NoopTextSystem;
|
||||
use crate::{
|
||||
px, Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
|
||||
ForegroundExecutor, Keymap, Keystroke, LinuxDispatcher, Menu, MenuItem, Modifiers, OwnedMenu,
|
||||
PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformInputHandler, PlatformTextSystem,
|
||||
PlatformWindow, Point, PromptLevel, Result, ScreenCaptureSource, SemanticVersion, SharedString,
|
||||
Size, Task, WindowAppearance, WindowOptions, WindowParams,
|
||||
ForegroundExecutor, Keymap, LinuxDispatcher, Menu, MenuItem, OwnedMenu, PathPromptOptions,
|
||||
Pixels, Platform, PlatformDisplay, PlatformTextSystem, PlatformWindow, Point, Result,
|
||||
ScreenCaptureSource, Task, WindowAppearance, WindowParams,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
pub(crate) const SCROLL_LINES: f32 = 3.0;
|
||||
|
||||
// Values match the defaults on GTK.
|
||||
// Taken from https://github.com/GNOME/gtk/blob/main/gtk/gtksettings.c#L320
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
pub(crate) const DOUBLE_CLICK_INTERVAL: Duration = Duration::from_millis(400);
|
||||
pub(crate) const DOUBLE_CLICK_DISTANCE: Pixels = px(5.0);
|
||||
pub(crate) const KEYRING_LABEL: &str = "zed-github-account";
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
const FILE_PICKER_PORTAL_MISSING: &str =
|
||||
"Couldn't open file picker due to missing xdg-desktop-portal implementation.";
|
||||
|
||||
@@ -54,8 +47,9 @@ pub trait LinuxClient {
|
||||
fn compositor_name(&self) -> &'static str;
|
||||
fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R;
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;
|
||||
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>>;
|
||||
#[allow(unused)]
|
||||
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>>;
|
||||
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>>;
|
||||
|
||||
fn open_window(
|
||||
&self,
|
||||
@@ -98,9 +92,9 @@ pub(crate) struct LinuxCommon {
|
||||
impl LinuxCommon {
|
||||
pub fn new(signal: LoopSignal) -> (Self, Channel<Runnable>) {
|
||||
let (main_sender, main_receiver) = calloop::channel::channel::<Runnable>();
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
let text_system = Arc::new(crate::CosmicTextSystem::new());
|
||||
|
||||
#[cfg(not(any(feature = "wayland", feature = "x11")))]
|
||||
let text_system = Arc::new(crate::NoopTextSystem::new());
|
||||
|
||||
@@ -218,7 +212,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
}
|
||||
}
|
||||
|
||||
fn activate(&self, ignoring_other_apps: bool) {
|
||||
fn activate(&self, _ignoring_other_apps: bool) {
|
||||
log::info!("activate is not implemented on Linux, ignoring the call")
|
||||
}
|
||||
|
||||
@@ -281,7 +275,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
let (done_tx, done_rx) = oneshot::channel();
|
||||
|
||||
#[cfg(not(any(feature = "wayland", feature = "x11")))]
|
||||
done_tx.send(Ok(None));
|
||||
let _ = (done_tx.send(Ok(None)), options);
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
self.foreground_executor()
|
||||
@@ -306,7 +300,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
ashpd::Error::PortalNotFound(_) => anyhow!(FILE_PICKER_PORTAL_MISSING),
|
||||
err => err.into(),
|
||||
};
|
||||
done_tx.send(Err(result));
|
||||
let _ = done_tx.send(Err(result));
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -322,7 +316,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
Err(ashpd::Error::Response(_)) => Ok(None),
|
||||
Err(e) => Err(e.into()),
|
||||
};
|
||||
done_tx.send(result);
|
||||
let _ = done_tx.send(result);
|
||||
})
|
||||
.detach();
|
||||
done_rx
|
||||
@@ -332,7 +326,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
let (done_tx, done_rx) = oneshot::channel();
|
||||
|
||||
#[cfg(not(any(feature = "wayland", feature = "x11")))]
|
||||
done_tx.send(Ok(None));
|
||||
let _ = (done_tx.send(Ok(None)), directory);
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
self.foreground_executor()
|
||||
@@ -356,7 +350,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
}
|
||||
err => err.into(),
|
||||
};
|
||||
done_tx.send(Err(result));
|
||||
let _ = done_tx.send(Err(result));
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -369,7 +363,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
Err(ashpd::Error::Response(_)) => Ok(None),
|
||||
Err(e) => Err(e.into()),
|
||||
};
|
||||
done_tx.send(result);
|
||||
let _ = done_tx.send(result);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
@@ -426,7 +420,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
|
||||
fn app_path(&self) -> Result<PathBuf> {
|
||||
// get the path of the executable of the current process
|
||||
let exe_path = std::env::current_exe()?;
|
||||
let exe_path = env::current_exe()?;
|
||||
Ok(exe_path)
|
||||
}
|
||||
|
||||
@@ -440,9 +434,9 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
self.with_common(|common| Some(common.menus.clone()))
|
||||
}
|
||||
|
||||
fn set_dock_menu(&self, menu: Vec<MenuItem>, keymap: &Keymap) {}
|
||||
fn set_dock_menu(&self, _menu: Vec<MenuItem>, _keymap: &Keymap) {}
|
||||
|
||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<PathBuf> {
|
||||
Err(anyhow::Error::msg(
|
||||
"Platform<LinuxPlatform>::path_for_auxiliary_executable is not implemented yet",
|
||||
))
|
||||
@@ -614,6 +608,7 @@ pub(super) fn reveal_path_internal(
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(super) fn is_within_click_distance(a: Point<Pixels>, b: Point<Pixels>) -> bool {
|
||||
let diff = a - b;
|
||||
diff.x.abs() <= DOUBLE_CLICK_DISTANCE && diff.y.abs() <= DOUBLE_CLICK_DISTANCE
|
||||
@@ -622,7 +617,7 @@ pub(super) fn is_within_click_distance(a: Point<Pixels>, b: Point<Pixels>) -> bo
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
pub(super) fn get_xkb_compose_state(cx: &xkb::Context) -> Option<xkb::compose::State> {
|
||||
let mut locales = Vec::default();
|
||||
if let Some(locale) = std::env::var_os("LC_CTYPE") {
|
||||
if let Some(locale) = env::var_os("LC_CTYPE") {
|
||||
locales.push(locale);
|
||||
}
|
||||
locales.push(OsString::from("C"));
|
||||
@@ -650,6 +645,7 @@ pub(super) unsafe fn read_fd(mut fd: filedescriptor::FileDescriptor) -> Result<V
|
||||
}
|
||||
|
||||
impl CursorStyle {
|
||||
#[allow(unused)]
|
||||
pub(super) fn to_icon_name(&self) -> String {
|
||||
// Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME)
|
||||
// and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from
|
||||
@@ -682,10 +678,12 @@ impl CursorStyle {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
impl Keystroke {
|
||||
pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self {
|
||||
let mut modifiers = modifiers;
|
||||
|
||||
impl crate::Keystroke {
|
||||
pub(super) fn from_xkb(
|
||||
state: &State,
|
||||
mut modifiers: crate::Modifiers,
|
||||
keycode: Keycode,
|
||||
) -> Self {
|
||||
let key_utf32 = state.key_get_utf32(keycode);
|
||||
let key_utf8 = state.key_get_utf8(keycode);
|
||||
let key_sym = state.key_get_one_sym(keycode);
|
||||
@@ -759,7 +757,7 @@ impl Keystroke {
|
||||
let key_char =
|
||||
(key_utf32 >= 32 && key_utf32 != 127 && !key_utf8.is_empty()).then_some(key_utf8);
|
||||
|
||||
Keystroke {
|
||||
Self {
|
||||
modifiers,
|
||||
key,
|
||||
key_char,
|
||||
@@ -776,7 +774,6 @@ impl Keystroke {
|
||||
Keysym::dead_acute => Some("´".to_owned()),
|
||||
Keysym::dead_circumflex => Some("^".to_owned()),
|
||||
Keysym::dead_tilde => Some("~".to_owned()),
|
||||
Keysym::dead_perispomeni => Some("͂".to_owned()),
|
||||
Keysym::dead_macron => Some("¯".to_owned()),
|
||||
Keysym::dead_breve => Some("˘".to_owned()),
|
||||
Keysym::dead_abovedot => Some("˙".to_owned()),
|
||||
@@ -794,9 +791,7 @@ impl Keystroke {
|
||||
Keysym::dead_horn => Some("̛".to_owned()),
|
||||
Keysym::dead_stroke => Some("̶̶".to_owned()),
|
||||
Keysym::dead_abovecomma => Some("̓̓".to_owned()),
|
||||
Keysym::dead_psili => Some("᾿".to_owned()),
|
||||
Keysym::dead_abovereversedcomma => Some("ʽ".to_owned()),
|
||||
Keysym::dead_dasia => Some("῾".to_owned()),
|
||||
Keysym::dead_doublegrave => Some("̏".to_owned()),
|
||||
Keysym::dead_belowring => Some("˳".to_owned()),
|
||||
Keysym::dead_belowmacron => Some("̱".to_owned()),
|
||||
@@ -830,7 +825,7 @@ impl Keystroke {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
impl Modifiers {
|
||||
impl crate::Modifiers {
|
||||
pub(super) fn from_xkb(keymap_state: &State) -> Self {
|
||||
let shift = keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE);
|
||||
let alt = keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);
|
||||
@@ -838,7 +833,7 @@ impl Modifiers {
|
||||
keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);
|
||||
let platform =
|
||||
keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE);
|
||||
Modifiers {
|
||||
Self {
|
||||
shift,
|
||||
alt,
|
||||
control,
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::hash::Hash;
|
||||
use std::os::fd::{AsRawFd, BorrowedFd};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
hash::Hash,
|
||||
os::fd::{AsRawFd, BorrowedFd},
|
||||
path::PathBuf,
|
||||
rc::{Rc, Weak},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use calloop::timer::{TimeoutAction, Timer};
|
||||
use calloop::{EventLoop, LoopHandle};
|
||||
use calloop::{
|
||||
timer::{TimeoutAction, Timer},
|
||||
EventLoop, LoopHandle,
|
||||
};
|
||||
use calloop_wayland_source::WaylandSource;
|
||||
use collections::HashMap;
|
||||
use filedescriptor::Pipe;
|
||||
@@ -64,30 +68,28 @@ use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS};
|
||||
|
||||
use super::display::WaylandDisplay;
|
||||
use super::window::{ImeInput, WaylandWindowStatePtr};
|
||||
use crate::platform::linux::wayland::clipboard::{
|
||||
Clipboard, DataOffer, FILE_LIST_MIME_TYPE, TEXT_MIME_TYPE,
|
||||
};
|
||||
use crate::platform::linux::wayland::cursor::Cursor;
|
||||
use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker};
|
||||
use crate::platform::linux::wayland::window::WaylandWindow;
|
||||
use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource};
|
||||
use crate::platform::linux::LinuxClient;
|
||||
|
||||
use crate::platform::linux::{
|
||||
get_xkb_compose_state, is_within_click_distance, open_uri_internal, read_fd,
|
||||
reveal_path_internal,
|
||||
wayland::{
|
||||
clipboard::{Clipboard, DataOffer, FILE_LIST_MIME_TYPE, TEXT_MIME_TYPE},
|
||||
cursor::Cursor,
|
||||
serial::{SerialKind, SerialTracker},
|
||||
window::WaylandWindow,
|
||||
},
|
||||
xdg_desktop_portal::{Event as XDPEvent, XDPEventSource},
|
||||
LinuxClient,
|
||||
};
|
||||
use crate::platform::PlatformWindow;
|
||||
use crate::platform::{blade::BladeContext, PlatformWindow};
|
||||
use crate::{
|
||||
point, px, size, Bounds, DevicePixels, FileDropEvent, ForegroundExecutor, MouseExitEvent, Size,
|
||||
DOUBLE_CLICK_INTERVAL, SCROLL_LINES,
|
||||
point, px, size, AnyWindowHandle, Bounds, CursorStyle, DevicePixels, DisplayId, FileDropEvent,
|
||||
ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, Modifiers,
|
||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent,
|
||||
MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScaledPixels,
|
||||
ScrollDelta, ScrollWheelEvent, Size, TouchPhase, WindowParams, DOUBLE_CLICK_INTERVAL,
|
||||
SCROLL_LINES,
|
||||
};
|
||||
use crate::{
|
||||
AnyWindowHandle, CursorStyle, DisplayId, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers,
|
||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
|
||||
NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScaledPixels, ScrollDelta,
|
||||
ScrollWheelEvent, TouchPhase,
|
||||
};
|
||||
use crate::{LinuxCommon, WindowParams};
|
||||
|
||||
/// Used to convert evdev scancode to xkb scancode
|
||||
const MIN_KEYCODE: u32 = 8;
|
||||
@@ -186,6 +188,7 @@ pub struct Output {
|
||||
pub(crate) struct WaylandClientState {
|
||||
serial_tracker: SerialTracker,
|
||||
globals: Globals,
|
||||
gpu_context: BladeContext,
|
||||
wl_seat: wl_seat::WlSeat, // TODO: Multi seat support
|
||||
wl_pointer: Option<wl_pointer::WlPointer>,
|
||||
wl_keyboard: Option<wl_keyboard::WlKeyboard>,
|
||||
@@ -459,6 +462,8 @@ impl WaylandClient {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let gpu_context = BladeContext::new().expect("Unable to init GPU context");
|
||||
|
||||
let seat = seat.unwrap();
|
||||
let globals = Globals::new(
|
||||
globals,
|
||||
@@ -512,6 +517,7 @@ impl WaylandClient {
|
||||
let mut state = Rc::new(RefCell::new(WaylandClientState {
|
||||
serial_tracker: SerialTracker::new(),
|
||||
globals,
|
||||
gpu_context,
|
||||
wl_seat: seat,
|
||||
wl_pointer: None,
|
||||
wl_keyboard: None,
|
||||
@@ -627,6 +633,7 @@ impl LinuxClient for WaylandClient {
|
||||
let (window, surface_id) = WaylandWindow::new(
|
||||
handle,
|
||||
state.globals.clone(),
|
||||
&state.gpu_context,
|
||||
WaylandClientStatePtr(Rc::downgrade(&self.0)),
|
||||
params,
|
||||
state.common.appearance,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::ffi::c_void;
|
||||
use std::ptr::NonNull;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
ffi::c_void,
|
||||
ptr::NonNull,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use blade_graphics as gpu;
|
||||
use collections::HashMap;
|
||||
@@ -19,10 +21,11 @@ use wayland_protocols::xdg::shell::client::xdg_surface;
|
||||
use wayland_protocols::xdg::shell::client::xdg_toplevel::{self};
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur;
|
||||
|
||||
use crate::platform::blade::{BladeRenderer, BladeSurfaceConfig};
|
||||
use crate::platform::linux::wayland::display::WaylandDisplay;
|
||||
use crate::platform::linux::wayland::serial::SerialKind;
|
||||
use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
|
||||
use crate::platform::{
|
||||
blade::{BladeContext, BladeRenderer, BladeSurfaceConfig},
|
||||
linux::wayland::{display::WaylandDisplay, serial::SerialKind},
|
||||
PlatformAtlas, PlatformInputHandler, PlatformWindow,
|
||||
};
|
||||
use crate::scene::Scene;
|
||||
use crate::{
|
||||
px, size, AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels,
|
||||
@@ -123,37 +126,28 @@ impl WaylandWindowState {
|
||||
viewport: Option<wp_viewport::WpViewport>,
|
||||
client: WaylandClientStatePtr,
|
||||
globals: Globals,
|
||||
gpu_context: &BladeContext,
|
||||
options: WindowParams,
|
||||
) -> anyhow::Result<Self> {
|
||||
let raw = RawWindow {
|
||||
window: surface.id().as_ptr().cast::<c_void>(),
|
||||
display: surface
|
||||
.backend()
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.display_ptr()
|
||||
.cast::<c_void>(),
|
||||
};
|
||||
let gpu = Arc::new(
|
||||
unsafe {
|
||||
gpu::Context::init_windowed(
|
||||
&raw,
|
||||
gpu::ContextDesc {
|
||||
validation: false,
|
||||
capture: false,
|
||||
overlay: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
.map_err(|e| anyhow::anyhow!("{:?}", e))?,
|
||||
);
|
||||
let config = BladeSurfaceConfig {
|
||||
size: gpu::Extent {
|
||||
width: options.bounds.size.width.0 as u32,
|
||||
height: options.bounds.size.height.0 as u32,
|
||||
depth: 1,
|
||||
},
|
||||
transparent: true,
|
||||
let renderer = {
|
||||
let raw_window = RawWindow {
|
||||
window: surface.id().as_ptr().cast::<c_void>(),
|
||||
display: surface
|
||||
.backend()
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.display_ptr()
|
||||
.cast::<c_void>(),
|
||||
};
|
||||
let config = BladeSurfaceConfig {
|
||||
size: gpu::Extent {
|
||||
width: options.bounds.size.width.0 as u32,
|
||||
height: options.bounds.size.height.0 as u32,
|
||||
depth: 1,
|
||||
},
|
||||
transparent: true,
|
||||
};
|
||||
BladeRenderer::new(gpu_context, &raw_window, config)?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
@@ -168,7 +162,7 @@ impl WaylandWindowState {
|
||||
globals,
|
||||
outputs: HashMap::default(),
|
||||
display: None,
|
||||
renderer: BladeRenderer::new(gpu, config),
|
||||
renderer,
|
||||
bounds: options.bounds,
|
||||
scale: 1.0,
|
||||
input_handler: None,
|
||||
@@ -266,6 +260,7 @@ impl WaylandWindow {
|
||||
pub fn new(
|
||||
handle: AnyWindowHandle,
|
||||
globals: Globals,
|
||||
gpu_context: &BladeContext,
|
||||
client: WaylandClientStatePtr,
|
||||
params: WindowParams,
|
||||
appearance: WindowAppearance,
|
||||
@@ -308,6 +303,7 @@ impl WaylandWindow {
|
||||
viewport,
|
||||
client,
|
||||
globals,
|
||||
gpu_context,
|
||||
params,
|
||||
)?)),
|
||||
callbacks: Rc::new(RefCell::new(Callbacks::default())),
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
use core::str;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{BTreeMap, HashSet},
|
||||
ops::Deref,
|
||||
path::PathBuf,
|
||||
rc::{Rc, Weak},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use calloop::generic::{FdWrapper, Generic};
|
||||
use calloop::{EventLoop, LoopHandle, RegistrationToken};
|
||||
use calloop::{
|
||||
generic::{FdWrapper, Generic},
|
||||
EventLoop, LoopHandle, RegistrationToken,
|
||||
};
|
||||
|
||||
use anyhow::Context as _;
|
||||
use collections::HashMap;
|
||||
@@ -15,44 +19,49 @@ use http_client::Url;
|
||||
use smallvec::SmallVec;
|
||||
use util::ResultExt;
|
||||
|
||||
use x11rb::connection::{Connection, RequestConnection};
|
||||
use x11rb::cursor;
|
||||
use x11rb::errors::ConnectionError;
|
||||
use x11rb::protocol::randr::ConnectionExt as _;
|
||||
use x11rb::protocol::xinput::ConnectionExt;
|
||||
use x11rb::protocol::xkb::ConnectionExt as _;
|
||||
use x11rb::protocol::xproto::{
|
||||
AtomEnum, ChangeWindowAttributesAux, ClientMessageData, ClientMessageEvent, ConnectionExt as _,
|
||||
EventMask, KeyPressEvent,
|
||||
use x11rb::{
|
||||
connection::{Connection, RequestConnection},
|
||||
cursor,
|
||||
errors::ConnectionError,
|
||||
protocol::randr::ConnectionExt as _,
|
||||
protocol::xinput::ConnectionExt,
|
||||
protocol::xkb::ConnectionExt as _,
|
||||
protocol::xproto::{
|
||||
AtomEnum, ChangeWindowAttributesAux, ClientMessageData, ClientMessageEvent,
|
||||
ConnectionExt as _, EventMask, KeyPressEvent,
|
||||
},
|
||||
protocol::{randr, render, xinput, xkb, xproto, Event},
|
||||
resource_manager::Database,
|
||||
wrapper::ConnectionExt as _,
|
||||
xcb_ffi::XCBConnection,
|
||||
};
|
||||
use x11rb::protocol::{randr, render, xinput, xkb, xproto, Event};
|
||||
use x11rb::resource_manager::Database;
|
||||
use x11rb::wrapper::ConnectionExt as _;
|
||||
use x11rb::xcb_ffi::XCBConnection;
|
||||
use xim::{x11rb::X11rbClient, Client};
|
||||
use xim::{AttributeName, InputStyle};
|
||||
use xim::{x11rb::X11rbClient, AttributeName, Client, InputStyle};
|
||||
use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION};
|
||||
use xkbcommon::xkb::{self as xkbc, LayoutIndex, ModMask};
|
||||
|
||||
use crate::platform::linux::LinuxClient;
|
||||
use crate::platform::{LinuxCommon, PlatformWindow};
|
||||
use crate::{
|
||||
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
|
||||
DisplayId, FileDropEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, Pixels,
|
||||
Platform, PlatformDisplay, PlatformInput, Point, RequestFrameOptions, ScaledPixels,
|
||||
ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
|
||||
};
|
||||
|
||||
use super::{
|
||||
button_or_scroll_from_event_detail, get_valuator_axis_index, modifiers_from_state,
|
||||
pressed_button_from_mask, ButtonOrScroll, ScrollDirection,
|
||||
};
|
||||
use super::{X11Display, X11WindowStatePtr, XcbAtoms};
|
||||
use super::{XimCallbackEvent, XimHandler};
|
||||
use crate::platform::linux::platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES};
|
||||
use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource};
|
||||
use crate::platform::linux::{
|
||||
get_xkb_compose_state, is_within_click_distance, open_uri_internal, reveal_path_internal,
|
||||
|
||||
use crate::platform::{
|
||||
blade::BladeContext,
|
||||
linux::{
|
||||
get_xkb_compose_state, is_within_click_distance, open_uri_internal,
|
||||
platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES},
|
||||
reveal_path_internal,
|
||||
xdg_desktop_portal::{Event as XDPEvent, XDPEventSource},
|
||||
LinuxClient,
|
||||
},
|
||||
LinuxCommon, PlatformWindow,
|
||||
};
|
||||
use crate::{
|
||||
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
|
||||
DisplayId, FileDropEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, Pixels,
|
||||
Platform, PlatformDisplay, PlatformInput, Point, RequestFrameOptions, ScaledPixels,
|
||||
ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
|
||||
};
|
||||
|
||||
/// Value for DeviceId parameters which selects all devices.
|
||||
@@ -158,6 +167,8 @@ pub struct X11ClientState {
|
||||
pub(crate) last_location: Point<Pixels>,
|
||||
pub(crate) current_count: usize,
|
||||
|
||||
gpu_context: BladeContext,
|
||||
|
||||
pub(crate) scale_factor: f32,
|
||||
|
||||
xkb_context: xkbc::Context,
|
||||
@@ -360,6 +371,8 @@ impl X11Client {
|
||||
let compose_state = get_xkb_compose_state(&xkb_context);
|
||||
let resource_database = x11rb::resource_manager::new_from_default(&xcb_connection).unwrap();
|
||||
|
||||
let gpu_context = BladeContext::new().expect("Unable to init GPU context");
|
||||
|
||||
let scale_factor = resource_database
|
||||
.get_value("Xft.dpi", "Xft.dpi")
|
||||
.ok()
|
||||
@@ -428,6 +441,7 @@ impl X11Client {
|
||||
last_mouse_button: None,
|
||||
last_location: Point::new(px(0.0), px(0.0)),
|
||||
current_count: 0,
|
||||
gpu_context,
|
||||
scale_factor,
|
||||
|
||||
xkb_context,
|
||||
@@ -1299,6 +1313,7 @@ impl LinuxClient for X11Client {
|
||||
handle,
|
||||
X11ClientStatePtr(Rc::downgrade(&self.0)),
|
||||
state.common.foreground_executor.clone(),
|
||||
&state.gpu_context,
|
||||
params,
|
||||
&state.xcb_connection,
|
||||
state.client_side_decorations_supported,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
|
||||
use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig};
|
||||
use crate::{
|
||||
platform::blade::{BladeRenderer, BladeSurfaceConfig},
|
||||
px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GpuSpecs,
|
||||
Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
|
||||
PlatformWindow, Point, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Scene, Size,
|
||||
@@ -247,7 +247,6 @@ pub struct X11WindowState {
|
||||
x_root_window: xproto::Window,
|
||||
pub(crate) counter_id: sync::Counter,
|
||||
pub(crate) last_sync_counter: Option<sync::Int64>,
|
||||
_raw: RawWindow,
|
||||
bounds: Bounds<Pixels>,
|
||||
scale_factor: f32,
|
||||
renderer: BladeRenderer,
|
||||
@@ -358,6 +357,7 @@ impl X11WindowState {
|
||||
handle: AnyWindowHandle,
|
||||
client: X11ClientStatePtr,
|
||||
executor: ForegroundExecutor,
|
||||
gpu_context: &BladeContext,
|
||||
params: WindowParams,
|
||||
xcb: &Rc<XCBConnection>,
|
||||
client_side_decorations_supported: bool,
|
||||
@@ -555,50 +555,39 @@ impl X11WindowState {
|
||||
|
||||
xcb.flush().with_context(|| "X11 Flush failed.")?;
|
||||
|
||||
let raw = RawWindow {
|
||||
connection: as_raw_xcb_connection::AsRawXcbConnection::as_raw_xcb_connection(xcb)
|
||||
as *mut _,
|
||||
screen_id: x_screen_index,
|
||||
window_id: x_window,
|
||||
visual_id: visual.id,
|
||||
let renderer = {
|
||||
let raw_window = RawWindow {
|
||||
connection: as_raw_xcb_connection::AsRawXcbConnection::as_raw_xcb_connection(
|
||||
xcb,
|
||||
) as *mut _,
|
||||
screen_id: x_screen_index,
|
||||
window_id: x_window,
|
||||
visual_id: visual.id,
|
||||
};
|
||||
let config = BladeSurfaceConfig {
|
||||
// Note: this has to be done after the GPU init, or otherwise
|
||||
// the sizes are immediately invalidated.
|
||||
size: query_render_extent(xcb, x_window)?,
|
||||
// We set it to transparent by default, even if we have client-side
|
||||
// decorations, since those seem to work on X11 even without `true` here.
|
||||
// If the window appearance changes, then the renderer will get updated
|
||||
// too
|
||||
transparent: false,
|
||||
};
|
||||
BladeRenderer::new(gpu_context, &raw_window, config)?
|
||||
};
|
||||
let gpu = Arc::new(
|
||||
unsafe {
|
||||
gpu::Context::init_windowed(
|
||||
&raw,
|
||||
gpu::ContextDesc {
|
||||
validation: false,
|
||||
capture: false,
|
||||
overlay: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
.map_err(|e| anyhow!("{:?}", e))?,
|
||||
);
|
||||
|
||||
let config = BladeSurfaceConfig {
|
||||
// Note: this has to be done after the GPU init, or otherwise
|
||||
// the sizes are immediately invalidated.
|
||||
size: query_render_extent(xcb, x_window)?,
|
||||
// We set it to transparent by default, even if we have client-side
|
||||
// decorations, since those seem to work on X11 even without `true` here.
|
||||
// If the window appearance changes, then the renderer will get updated
|
||||
// too
|
||||
transparent: false,
|
||||
};
|
||||
check_reply(|| "X11 MapWindow failed.", xcb.map_window(x_window))?;
|
||||
|
||||
let display = Rc::new(X11Display::new(xcb, scale_factor, x_screen_index)?);
|
||||
|
||||
Ok(Self {
|
||||
client,
|
||||
executor,
|
||||
display,
|
||||
_raw: raw,
|
||||
x_root_window: visual_set.root,
|
||||
bounds: bounds.to_pixels(scale_factor),
|
||||
scale_factor,
|
||||
renderer: BladeRenderer::new(gpu, config),
|
||||
renderer,
|
||||
atoms: *atoms,
|
||||
input_handler: None,
|
||||
active: false,
|
||||
@@ -716,6 +705,7 @@ impl X11Window {
|
||||
handle: AnyWindowHandle,
|
||||
client: X11ClientStatePtr,
|
||||
executor: ForegroundExecutor,
|
||||
gpu_context: &BladeContext,
|
||||
params: WindowParams,
|
||||
xcb: &Rc<XCBConnection>,
|
||||
client_side_decorations_supported: bool,
|
||||
@@ -730,6 +720,7 @@ impl X11Window {
|
||||
handle,
|
||||
client,
|
||||
executor,
|
||||
gpu_context,
|
||||
params,
|
||||
xcb,
|
||||
client_side_decorations_supported,
|
||||
|
||||
Reference in New Issue
Block a user